“항상 5를 반환하는 함수”를 갖는 것이 “함수 호출”의 의미를 깨뜨 리거나 희석시키는 것 같습니다. 이유가 있거나이 기능이 필요하거나 C ++ 11에 있지 않아야합니다. 왜 거기에 있습니까?
// preprocessor.
#define MEANING_OF_LIFE 42
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
리터럴 값을 반환하는 함수를 작성하고 코드 검토를 수행하면 누군가가 반환 5를 작성하는 대신 상수 값을 선언해야한다고 말할 것입니다.
답변
좀 더 복잡한 일을한다고 가정 해보십시오.
constexpr int MeaningOfLife ( int a, int b ) { return a * b; }
const int meaningOfLife = MeaningOfLife( 6, 7 );
이제 상수를 숫자로 설정하는 것보다 가독성을 높이고 약간 더 복잡한 처리를 허용하면서 상수로 평가할 수있는 것이 있습니다.
기본적으로 유지 관리에 도움이됩니다. 가지고 max( a, b )
예를 들면 :
template< typename Type > constexpr Type max( Type a, Type b ) { return a < b ? b : a; }
매우 간단한 선택이지만 max
상수 값으로 호출하면 런타임이 아닌 컴파일 타임에 명시 적으로 계산됩니다.
또 다른 좋은 예는 DegreesToRadians
함수입니다. 누구나 라디안보다 읽기 쉬운 정도를 찾습니다. 180 도가 라디안 인 것을 알 수 있지만 다음과 같이 훨씬 명확하게 작성됩니다.
const float oneeighty = DegreesToRadians( 180.0f );
여기에 좋은 정보가 많이 있습니다 :
답변
소개
constexpr
상수 표현 이 필요한 상황에서 무언가를 평가할 수 있음을 구현에 알리는 방법으로 소개되지 않았습니다 . 적합한 구현은 C ++ 11 이전에 이것을 증명할 수있었습니다.
구현이 증명할 수없는 것은 특정 코드 의 의도 입니다.
- 개발자가이 엔티티로 표현하고자하는 것은 무엇입니까?
- 코드 가 작동하기 때문에 상수 표현식 에서 코드를 맹목적으로 허용해야합니까 ?
세상이 없으면 constexpr
무엇이 될까요?
라이브러리를 개발 중이고 interval의 모든 정수의 합을 계산할 수 있기를 원한다고 가정 해 봅시다 (0,N]
.
int f (int n) {
return n > 0 ? n + f (n-1) : n;
}
의도 부족
컴파일러는 전달 된 인수가 변환 중에 알려진 경우 상수 표현식 에서 위 함수를 호출 할 수 있음을 쉽게 증명할 수 있습니다 . 그러나 당신은 이것을 의도로 선언하지 않았습니다-그것은 단지 사건이되었습니다.
이제 다른 누군가가 와서 함수를 읽고 컴파일러와 동일한 분석을 수행합니다. ” 아,이 함수는 상수 표현으로 사용할 수 있습니다!” 다음 코드를 작성합니다.
T arr[f(10)]; // freakin' magic
최적화
당신은, int로서 “최고” 라이브러리 개발자, 즉 결정 f
호출되는 경우 결과를 캐시한다 누가 같은 값 집합을 계속해서 계산하고 싶습니까?
int func (int n) {
static std::map<int, int> _cached;
if (_cached.find (n) == _cached.end ())
_cached[n] = n > 0 ? n + func (n-1) : n;
return _cached[n];
}
결과
바보 같은 최적화를 도입함으로써 상수 표현 이 필요한 상황에서 발생한 함수의 모든 사용을 중단했습니다 .
당신은 함수가에서 사용할 것을 약속 결코 일정한 표현 , 그리고없이 constexpr
같은 약속을 제공하는 방법이 없습니다.
왜 우리는 필요 constexpr
합니까?
constexpr 의 주요 사용법은 intent 선언 입니다.
엔터티가로 표시되지 않은 경우 constexpr
– 상수 표현식에 . 그리고 그것이더라도, 우리는 컴파일러를 사용하여 그러한 상황을 진단합니다 (우리의 의도를 무시하기 때문에).
답변
취하기 std::numeric_limits<T>::max()
: 어떤 이유로 든 이것은 방법입니다. constexpr
여기에 도움이 될 것입니다.
또 다른 예 : std::array
다른 배열만큼 큰 C 배열 (또는 ) 을 선언하려고합니다 . 현재이 작업을 수행하는 방법은 다음과 같습니다.
int x[10];
int y[sizeof x / sizeof x[0]];
그러나 다음과 같이 쓸 수있는 것이 더 좋지 않을 것입니다.
int y[size_of(x)];
덕분에 다음 constexpr
을 수행 할 수 있습니다.
template <typename T, size_t N>
constexpr size_t size_of(T (&)[N]) {
return N;
}
답변
constexpr
함수는 정말 좋고 c ++에 크게 추가되었습니다. 그러나 해결하는 대부분의 문제는 매크로를 사용하여 우아하게 해결할 수 있습니다.
그러나의 사용 중 하나 constexpr
에는 C ++ 03과 동등한 유형의 상수가 없습니다.
// This is bad for obvious reasons.
#define ONE 1;
// This works most of the time but isn't fully typed.
enum { TWO = 2 };
// This doesn't compile
enum { pi = 3.1415f };
// This is a file local lvalue masquerading as a global
// rvalue. It works most of the time. But May subtly break
// with static initialization order issues, eg pi = 0 for some files.
static const float pi = 3.1415f;
// This is a true constant rvalue
constexpr float pi = 3.1415f;
// Haven't you always wanted to do this?
// constexpr std::string awesome = "oh yeah!!!";
// UPDATE: sadly std::string lacks a constexpr ctor
struct A
{
static const int four = 4;
static const int five = 5;
constexpr int six = 6;
};
int main()
{
&A::four; // linker error
&A::six; // compiler error
// EXTREMELY subtle linker error
int i = rand()? A::four: A::five;
// It not safe use static const class variables with the ternary operator!
}
//Adding this to any cpp file would fix the linker error.
//int A::four;
//int A::six;
답변
내가 읽은 것에서 constexpr의 필요성은 메타 프로그래밍의 문제에서 비롯됩니다. 특성 클래스는 함수로 표현되는 상수를 가질 수 있습니다. numeric_limits :: max (). constexpr을 사용하면 이러한 유형의 함수를 메타 프로그래밍 또는 배열 경계 등으로 사용할 수 있습니다.
내 머리 꼭대기의 또 다른 예는 클래스 인터페이스의 경우 파생 된 유형이 일부 작업에 대해 자체 상수를 정의하기를 원할 수 있습니다.
편집하다:
SO를 둘러 본 후 다른 사람들이 constexprs로 가능한 것들에 대한 몇 가지 예 를 생각해 냈습니다 .
답변
“Going Native 2012″에서 Stroustrup의 연설에서 :
template<int M, int K, int S> struct Unit { // a unit in the MKS system
enum { m=M, kg=K, s=S };
};
template<typename Unit> // a magnitude with a unit
struct Value {
double val; // the magnitude
explicit Value(double d) : val(d) {} // construct a Value from a double
};
using Speed = Value<Unit<1,0,-1>>; // meters/second type
using Acceleration = Value<Unit<1,0,-2>>; // meters/second/second type
using Second = Unit<0,0,1>; // unit: sec
using Second2 = Unit<0,0,2>; // unit: second*second
constexpr Value<Second> operator"" s(long double d)
// a f-p literal suffixed by ‘s’
{
return Value<Second> (d);
}
constexpr Value<Second2> operator"" s2(long double d)
// a f-p literal suffixed by ‘s2’
{
return Value<Second2> (d);
}
Speed sp1 = 100m/9.8s; // very fast for a human
Speed sp2 = 100m/9.8s2; // error (m/s2 is acceleration)
Speed sp3 = 100/9.8s; // error (speed is m/s and 100 has no unit)
Acceleration acc = sp1/0.5s; // too fast for a human
답변
아직 언급되지 않은 또 다른 용도는 constexpr
생성자입니다. 이를 통해 런타임 중에 초기화 할 필요가없는 컴파일 시간 상수를 작성할 수 있습니다.
const std::complex<double> meaning_of_imagination(0, 42);
사용자 정의 리터럴과 쌍을 이루면 리터럴 사용자 정의 클래스를 완벽하게 지원합니다.
3.14D + 42_i;