C ++ 11에서 언제 constexpr 기능을 사용해야합니까?


337

"항상 5를 반환하는 함수"를 갖는 것이 "함수 호출"의 의미를 깨뜨 리거나 희석시키는 것 같습니다. 이유가 있거나이 기능이 필요하거나 C ++ 11에 있지 않아야합니다. 왜 거기에 있습니까?

// preprocessor.
#define MEANING_OF_LIFE 42

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

리터럴 값을 반환하는 함수를 작성하고 코드 검토를 수행하면 누군가가 반환 5를 작성하는 대신 상수 값을 선언해야한다고 말할 것입니다.


28
constexpr? 를 반환하는 재귀 함수를 정의 할 수 있습니까 ? 그렇다면 사용법을 볼 수 있습니다.
ereOn

20
나는 "컴파일러가 컴파일 타임에 함수를 평가할 수 있는지 여부를 컴파일러가 스스로 결정할 수 있다면 왜 새로운 키워드 (!)를 도입해야 하는가"라고 질문해야한다고 생각합니다. "키워드로 보증하는"것은 좋지만 키워드가 필요하지 않으면 가능할 때마다 보장하는 것이 좋습니다.
코스

6
@ Kos : C ++ 내부에 더 정통한 사람은 아마도 귀하의 질문을 선호하지만 내 질문은 이전에 C 코드를 작성했지만 C ++ 2011 키워드에 익숙하지 않은 사람이나 C ++ 컴파일러 구현 세부 사항에 대한 관점에서 비롯된 것입니다. . 컴파일러 최적화와 상수 표현 추론에 대해 추론 할 수있는 것은이 질문보다 고급 사용자 질문의 주제입니다.
워렌 P

8
@ Kos 나는 당신과 같은 줄을 생각하고 있었고, 내가 생각해 낸 대답은 constexpr없이 컴파일러가 실제로 함수를 컴파일 타임으로 평가 했다는 것을 어떻게 쉽게 수 있습니까? 어셈블리 출력을 확인하여 수행 한 작업을 확인할 수 있다고 가정하지만 컴파일러에게 최적화가 필요하다는 것을 알리는 것이 더 쉽고 어떤 이유로 든 그렇게 할 수 없다면 멋진 컴파일을 제공합니다. 오류가 예상되는 위치를 자동으로 최적화하지 않고 오류가 발생했습니다.
Jeremy Friesner

3
@ Kos :에 대해 같은 것을 말할 수 const있습니다. 실제로, 강제 의도유용합니다 ! 일반적인 치수는 배열 치수입니다.
궤도에서 가벼움 레이스

답변:


303

좀 더 복잡한 일을한다고 가정 해보십시오.

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 );

여기에 좋은 정보가 많이 있습니다 :

http://en.cppreference.com/w/cpp/language/constexpr


18
컴파일러가 컴파일 타임에 값을 시도하고 계산하도록 지시하는 데 탁월한 요점입니다. 특정 최적화가 지정 될 때 const가이 기능을 제공하지 않는 이유가 궁금합니다. 아니면?
TamusJRoyce

11
@ 타 무스 : 종종 그럴 의무는 없습니다. constexpr은 컴파일러를 의무화하고, 그렇지 않으면 오류를 내뱉습니다.
Goz

20
나는 지금 본다. 죄 (0.5)는 또 다른 것입니다. 이것은 C 매크로를 깔끔하게 대체합니다.
워렌 P

10
이것을 새로운 면접 질문으로 볼 수 있습니다. const와 constexpr 키워드의 차이점을 설명하십시오.
워렌 P

2
이 점을 스스로 문서화하는 방법으로 위와 비슷한 코드를 작성하여 "constexpr"이 아닌 "const"라는 함수를 작성했습니다. Clang3.3, -pedantic-errors 및 -std = c ++ 11을 사용하면서 후자가 컴파일되지 않을 것으로 예상했습니다. "constexpr"의 경우와 같이 컴파일하고 실행했습니다. 이것이 clang 확장 이거나이 게시물이 답변 된 이후 C ++ 11 사양이 조정되었다고 가정합니까?
Arbalest

144

소개

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- 상수 표현식에 . 그리고 그것이더라도, 우리는 컴파일러를 사용하여 그러한 상황을 진단합니다 (우리의 의도를 무시하기 때문에).


25
C ++ 14 및 C ++ 17의 최근 변경으로 인해 더 넓은 범위의 언어를 constexpr표현식에 사용할 수 있으므로 이것이 정답 일 것입니다 . 다시 말해서, 거의 모든 것에 주석을 달 수 있습니다 constexpr(어쩌면 언젠가 단순히 이것 때문에 그냥 사라질 것입니까?). 언제 사용할 것인지에 대한 기준이 constexpr없으면 거의 모든 코드가 다음과 같이 작성됩니다. .
alecov

4
@alecov Definitly 모든 것이 ... I/O, syscall그리고 dynamic memory allocationdefinitly로 표시 두지 constexpr게다가, 모든 것이 해야constexpr.
JiaHao Xu

1
@alecov 일부 함수는 런타임에 실행되도록되어 있으며 컴파일 타임에이를 수행하는 것은 의미가 없습니다.
JiaHao Xu

1
나는 또한이 대답이 가장 좋습니다. 컴파일 시간 평가는 깔끔한 최적화이지만 실제로 얻는 constexpr것은 일종의 동작을 보장하는 것입니다. 그냥 같이 const한다.
Tomáš Zato-복원 모니카

constexpr-less 버전 의이 컴파일러를 사용하면 int f (int n) { return n > 0 ? n + f (n-1) : n;} T arr[f(10)]; 어디서나 컴파일 할 수 없습니까?
Jer

91

취하기 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;
}

1
훌륭한 템플릿 사용을 위해 +1이지만 constexpr없이 정확히 동일하게 작동합니까?
코스

21
@Kos : 아니요. 런타임 값을 반환합니다. constexpr컴파일러가 함수가 컴파일 타임 값을 반환하도록합니다 (가능한 경우).
deft_code

14
@Kos : constexpr함수 호출의 결과가 컴파일 타임 상수인지 여부에 관계없이 배열 크기 선언이나 템플릿 인수로 사용할 수 없습니다. 이 두 가지는 기본적으로 유일한 유스 케이스 constexpr이지만 최소한 템플리트 인수 유스 케이스는 중요합니다.
Konrad Rudolph

2
"어떤 이유로 든 이것이 메서드입니다": 그 이유는 C ++ 03에는 컴파일 타임 정수만 있고 다른 컴파일 타임 타입은 없기 때문에 C ++ 11 이전의 임의의 타입에는 메서드 만 작동 할 수 있기 때문입니다.
Sebastian Mach

5
@LwCui 아니요,“ok”가 아닙니다. GCC는 기본적으로 특정 사항에 대해 느슨합니다. -pedantic옵션을 사용하면 오류로 표시됩니다.
Konrad Rudolph

19

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;

12
"아주 미묘한 링커 오류"를 명확히 하시겠습니까? 아니면 적어도 설명에 대한 포인터를 제공합니까?
enobayram

4
@enobayram, 삼항 연산자는 피연산자의 주소를 사용합니다. 그것은 코드에서 분명하지 않습니다. 모든 것이 잘 컴파일되지만 주소가 확인 four되지 않아 링크가 실패합니다 . 누가 내 static const변수 의 주소를 사용하고 있는지 파악해야했습니다 .
deft_code

23
"이것은 명백한 이유로 나쁘다": 가장 명백한 이유는 세미콜론입니다.
TonyK

4
"매우 미묘한 링커 오류"가 완전히 당황했습니다. 또한 범위 내에 four있지도 않습니다 five.
Steven Lu

3
새로운 enum class유형을 참조 하면 열거 형 문제 중 일부가 수정됩니다.
ninMonkey

14

내가 읽은 것에서 constexpr의 필요성은 메타 프로그래밍의 문제에서 비롯됩니다. 특성 클래스는 함수로 표현되는 상수를 가질 수 있습니다. numeric_limits :: max (). constexpr을 사용하면 이러한 유형의 함수를 메타 프로그래밍 또는 배열 경계 등으로 사용할 수 있습니다.

내 머리 꼭대기의 또 다른 예는 클래스 인터페이스의 경우 파생 된 유형이 일부 작업에 대해 자체 상수를 정의하기를 원할 수 있습니다.

편집하다:

SO를 둘러 본 후 다른 사람들이 constexprs로 가능한 것들에 대한 몇 가지 를 생각해 냈습니다 .


"인터페이스의 일부가 되려면 기능이 있어야합니까?"
Daniel Earwicker

이제 이것의 유용성을 볼 수 있으므로 C ++ 0x에 대해 조금 더 흥분합니다. 잘 생각 된 것 같습니다. 나는 그들이 있어야한다는 것을 알았습니다. 그 언어 표준 우버 괴짜들은 거의 무작위적인 일을하지 않습니다.
워렌 P

람다, 스레딩 모델, initializer_list, rvalue 참조, variadic 템플릿, 새로운 바인드 오버로드에 대해 더 흥분되어 있습니다.
luke

1
예,하지만 이미 여러 언어로 람다 / 클로저를 이해하고 있습니다. constexpr강력한 컴파일 타임 식 평가 시스템을 갖춘 컴파일러에서 더 유용합니다. C ++에는 실제로 해당 도메인에 피어가 없습니다. (이것은 C ++ 11, IMHO에게 큰 칭찬입니다)
Warren P

11

"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

2
이 예제는 Stroustrup의 종이 Software Development for Infrastructure 에서 찾을 수 있습니다 .
Matthieu Poullet

clang-3.3 : 오류 : constexpr 함수의 반환 유형 'Value <Second>'는 리터럴 유형이 아닙니다
Mitja

이것은 좋지만 누가 이와 같은 코드에 리터럴을 넣습니다. 대화식 계산기를 작성하는 경우 컴파일러에서 "단위를 확인"하도록하는 것이 좋습니다.
bobobobo

5
@bobobobo 또는 Mars Climate Orbiter 용 내비게이션 소프트웨어를 작성하는 경우 아마도 :)
Jeremy Friesner

1
컴파일하려면-1. 리터럴 접미사에 밑줄을 사용하십시오. 2. 100_m에 연산자 ""_m을 추가하십시오. 3. 100.0_m을 사용하거나 부호없는 long long을 허용하는 과부하를 추가하십시오. 4. Value 생성자 constexpr을 선언하십시오. constexpr auto operator / (const Value <Y> & other) const {return Value <Unit <TheUnit :: m-Value <Y> :: TheUnit :: m, TheUnit :: kg-값 <Y> :: TheUnit :: kg, TheUnit :: s-값 <Y> :: TheUnit :: s >> (val / other.val); }. 여기서 TheUnit은 Value 클래스 내에 추가 된 Unit에 대한 typedef입니다.
0kcats

8

아직 언급되지 않은 또 다른 용도는 constexpr생성자입니다. 이를 통해 런타임 중에 초기화 할 필요가없는 컴파일 시간 상수를 작성할 수 있습니다.

const std::complex<double> meaning_of_imagination(0, 42); 

사용자 정의 리터럴과 쌍을 이루면 리터럴 사용자 정의 클래스를 완벽하게 지원합니다.

3.14D + 42_i;

6

메타 프로그래밍을 사용한 패턴이있었습니다.

template<unsigned T>
struct Fact {
    enum Enum {
        VALUE = Fact<T-1>*T;
    };
};

template<>
struct Fact<1u> {
    enum Enum {
        VALUE = 1;
    };
};

// Fact<10>::VALUE is known be a compile-time constant

나는 constexpr전문화, SFINAE 및 물건을 사용하여 템플릿과 이상한 구성을 필요로하지 않고 그러한 구성을 작성할 수 있다고 소개되었지만 런타임 함수를 작성하는 것과 정확히 같지만 결과가 컴파일로 결정된다는 보장 -시각.

그러나 다음 사항에 유의하십시오.

int fact(unsigned n) {
    if (n==1) return 1;
    return fact(n-1)*n;
}

int main() {
    return fact(10);
}

이것을 컴파일하면 컴파일 타임에 실제로 증발 g++ -O3한다는 것을 알 수 있습니다 fact(10)!

VLA 인식 컴파일러 (C99 모드의 C 컴파일러 또는 C99 확장자의 C ++ 컴파일러)를 사용하여 다음을 수행 할 수도 있습니다.

int main() {
    int tab[fact(10)];
    int tab2[std::max(20,30)];
}

그러나 현재로서는 비표준 C ++입니다. constexpr(이 경우 VLA가없는 경우에도)이를 방지하는 방법처럼 보입니다. 그리고 템플릿 형식 인수로 "공식적인"상수 표현식을 사용해야한다는 문제가 여전히 남아 있습니다.


팩트 함수는 컴파일 타임에 평가되지 않습니다. constexpr이어야하며 하나의 return 문만 있어야합니다.
Sumant

1
@ Sumant : 컴파일 타임에 평가 할 필요는 없지만 맞습니다! 컴파일러에서 실제로 일어나는 일을 언급하고있었습니다. 최근 GCC에서 컴파일하고 결과 asm을보고 나를 믿지 않으면 스스로 확인하십시오!
Kos

추가하려고하면 std::array<int, fact(2)>컴파일시 fact ()가 평가되지 않음을 알 수 있습니다. 좋은 일을하는 것은 단지 GCC 최적화 프로그램입니다.

1
그게 내가 말한 것입니다 ... 정말 불분명합니까? 마지막 단락 참조
Kos

5

방금 프로젝트를 c ++ 11로 전환하기 시작했으며 constexpr에 대해 완벽하게 좋은 상황을 발견하여 동일한 작업을 수행하는 대체 방법을 정리했습니다. 여기서 중요한 점은 constexpr로 선언 될 때 배열 크기 선언에만 함수를 배치 할 수 있다는 것입니다. 내가 관여하고있는 코드 영역에서이 기능이 매우 유용하다는 것을 알 수있는 상황이 많이 있습니다.

constexpr size_t GetMaxIPV4StringLength()
{
    return ( sizeof( "255.255.255.255" ) );
}

void SomeIPFunction()
{
    char szIPAddress[ GetMaxIPV4StringLength() ];
    SomeIPGetFunction( szIPAddress );
}

4
다음과 같이 쓸 수 있습니다. const size_t MaxIPV4StringLength = sizeof ( "255.255.255.255");
Superfly Jon

static inline constexpr const auto아마 더 낫다.
JiaHao Xu

3

다른 모든 대답은 훌륭합니다. 단지 constexpr로 할 수있는 한 가지 멋진 예를 드리고 싶습니다. See-Phit ( https://github.com/rep-movsd/see-phit/blob/master/seephit.h )은 컴파일 타임 HTML 파서 및 템플릿 엔진입니다. 즉, HTML을 넣고 조작 할 수있는 트리를 가져올 수 있습니다. 컴파일 타임에 구문 분석을 수행하면 약간의 추가 성능을 얻을 수 있습니다.

github 페이지 예에서 :

#include <iostream>
#include "seephit.h"
using namespace std;



int main()
{
  constexpr auto parser =
    R"*(
    <span >
    <p  color="red" height='10' >{{name}} is a {{profession}} in {{city}}</p  >
    </span>
    )*"_html;

  spt::tree spt_tree(parser);

  spt::template_dict dct;
  dct["name"] = "Mary";
  dct["profession"] = "doctor";
  dct["city"] = "London";

  spt_tree.root.render(cerr, dct);
  cerr << endl;

  dct["city"] = "New York";
  dct["name"] = "John";
  dct["profession"] = "janitor";

  spt_tree.root.render(cerr, dct);
  cerr << endl;
}

1

기본 예제는 상수 자체와 동일한 주장을합니다. 왜 사용

static const int x = 5;
int arr[x];

위에

int arr[5];

유지 관리가 더 쉽기 때문입니다. constexpr을 사용하면 기존 메타 프로그래밍 기술보다 훨씬 빠르게 쓰고 읽을 수 있습니다.


0

새로운 최적화가 가능합니다. const전통적으로 유형 시스템에 대한 힌트이며 최적화에 사용할 수 없습니다 (예 : const멤버 함수는 const_cast합법적으로 오브젝트를 수정하고 수정할 const수 있으므로 최적화에 대해 신뢰할 수 없음).

constexpr함수에 대한 입력이 const 인 경우 표현식이 실제로 일정 함을 의미합니다 . 치다:

class MyInterface {
public:
    int GetNumber() const = 0;
};

이것이 다른 모듈에 노출되면 컴파일러는 구현시 캐스트 될 수 GetNumber()있기 때문에 호출 될 때마다 다른 값을 반환하지 않는 것을 신뢰할 수 없습니다 const. (분명히이 작업을 수행 한 모든 프로그래머는 촬영해야하지만 언어는이를 허용하므로 컴파일러는 규칙을 준수해야합니다.)

추가 constexpr:

class MyInterface {
public:
    constexpr int GetNumber() const = 0;
};

컴파일러는 이제 반환 값 GetNumber()이 캐시 되는 최적화를 적용하고에 대한 추가 호출을 제거 할 수 있습니다. 반환 값이 변경되지 않는다는 보장이 더 강력 GetNumber()하기 때문 constexpr입니다.


실제로 최적화에 사용될 const 있습니다 ... IIRC 후에도 정의 된 const 값을 수정하는 것은 정의되지 않은 동작 const_cast입니다. const멤버 함수에 일관성이 있기를 기대 하지만 표준으로 확인해야합니다. 이는 컴파일러가 안전하게 최적화를 수행 할 수 있음을 의미합니다.
Kos

1
@Warren : 최적화가 실제로 수행되는지는 중요하지 않으며 단지 허용됩니다. @ Kos : 원본 객체가 const ( vs. )로 선언 되지 않은 경우 포인터 / 참조에서 const를 -ing 하여 수정하여 안전하다는 것은 알려진 미묘한 부분입니다 . 그렇지 않으면 항상 정의되지 않은 동작을 호출하고 쓸모가 없습니다 :)이 경우 컴파일러는 원본 객체의 구성에 대한 정보가 없으므로 알 수 없습니다. int xconst int xconst_castconst_cast
AshleysBrain

@ Kos const_cast가 유일한 문제라고 생각하지 않습니다. const 메소드는 전역 변수를 읽고 수정할 수 있습니다. 반대로 anpther 스레드의 누군가가 호출 사이에서 const 객체를 수정할 수도 있습니다.
enobayram

1
"= 0"은 여기서 유효하지 않으므로 제거해야합니다. 나는 그것을 스스로 할 것이지만 그것이 SO 프로토콜과 일치하는지 확실하지 않습니다.
KnowItAllWannabe

두 예제 모두 유효하지 않습니다. 첫 번째 예제 ( int GetNumber() const = 0;)는 GetNumber()메소드 virtual을 선언해야합니다 . constexpr int GetNumber() const = 0;순수 지정자 ( = 0)가 메소드가 가상임을 암시 하므로 두 번째 ( )는 유효하지 않지만 constexpr은 가상이 아니어야합니다 (참조 : en.cppreference.com/w/cpp/language/constexpr )
stj

-1

사용시기 constexpr:

  1. 컴파일 타임 상수가있을 때마다.

동의하지만이 답변은 전 처리기 매크로 또는보다 선호해야하는 이유 constexpr 를 설명하지 않습니다 const.
Sneftel

-3

그것은 같은 것에 유용합니다

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

int some_arr[MeaningOfLife()];

이것을 특성 클래스 등으로 묶으면 매우 유용합니다.


4
귀하의 예에서는 일반 상수보다 이점이 없으므로 실제로 질문에 대답하지 않습니다.
jalf

이것은 의미있는 예입니다. MeaningOfLife ()가 다른 곳에서 값을 얻는다면, 다른 함수 나 #define 또는 series therof를 상상해보십시오. 그것이 무엇을 반환하는지 모를 수도 있고, 라이브러리 코드 일 수도 있습니다. 다른 예에서는 constexpr size () 메서드가있는 불변 컨테이너를 상상해보십시오. 이제 int arr [container.size ()];
plivesey 2012 년

2
@ plivesey 더 나은 예를 들어 답변을 편집하십시오.
Mukesh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.