CS/C&C++

constexpr

푸르뎅뎅 2021. 5. 27. 11:15

1. constexpr

 

기존의 const 보다 훨씬 더 상수성에 충실하며, 컴파일 타임 함수를 이용한 성능 향상 등 충분히 깊게 이해할만한 가치가 있는 녀석이라 할 수 있으니, 확실히 이해하고 활용할 수 있는 것이 중요하다.

 

C++11부터 지원되는 한정자 constexpr 일반화된 상수 표현식(Generalized constant expression)을 사용할 수 있게 해주며, 일반화된 상수 표현식을 통해 변수 함수, 생성자 함수에 대하여 컴파일 타임에 평가될 수 있도록 처리해 줄 수 있다.

(C++17부터는 람다 함수에도 constexpr 키워드 사용이 가능하다)

 

constexpr 변수 또는 함수의 반환값은 반드시 LiteralType이어야 하며, LiteralType은 컴파일 타임에 해당 레이아웃이 결정될 수 있는 타입을 의미한다. 다음은 리터럴 타입들의 유형이다.

  • void
  • 스칼라 값
  • 참조
  • void, 스칼라 값, 참조의 배열
  • trivial 소멸자 및 이동 또는 복사 생성자가 아닌 constexpr 생성자를 포함하는 클래스. 또한 해당 비정적 데이터 멤버 및 기본 클래스가 모두 리터럴 타입이고 volatile이 아니어야 함

 

코드 작업 중 해당 타입이 리터럴 타입인지 확인하고 싶을 땐, std::is_literal_type을 사용하면 된다.

 

 

1) 변수에서의 사용

 

const와 constexpr의 주요 차이점은 const 변수의 초기화를 런타임까지 지연시킬 수 있는 반면, constexpr 변수는 반드시 컴파일 타임에 초기화가 되어 있어야 한다.

초기화가 안 되었거나, 상수가 아닌 값으로 초기화 시도시 컴파일이 되지 않는다.

 

  1. constexpr float x = 42.f;    // OK
  2. constexpr float y { 108.f }; // OK
  3. constexpr int i;             // error C2737: 'i': 'constexpr' 개체를 초기화해야 합니다.
  4. int j = 0;
  5. constexpr int k = j + 1;     // error C2131 : 식이 상수로 계산되지 않았습니다.

 

변수에 constexpr 사용시 const 한정자를 암시한다.

 

 

2) 함수에서의 사용

 

constexpr을 함수 반환값에 사용할 때는 다음의 제약들이 따른다.

  • 가상으로 재정의된 함수가 아니어야 한다.
  • 반환값의 타입은 반드시 LiteralType이어야 한다.

 

함수에 constexpr을 붙일 경우 inline을 암시한다.

즉, 컴파일 타임에 평가하기 때문이며, inline 함수들과 같이 컴파일된다.

 

C++11에서는 함수 본문에 지역변수를 둘 수 없고, 하나의 반환 표현식만이 와야 하는 제약이 있었으나, C++14부터는 이러한 제약이 사라졌다.

 

  1. // C++11/14 모두 가능
  2. constexpr int factorial(int n)
  3. {
  4.     // 지역 변수 없음
  5.     // 하나의 반환문
  6.     return n <= 1 ? 1 : (* factorial(- 1));
  7. }
  8.  
  9. // C++11에서는 컴파일 에러 발생
  10. // C++14부터 가능
  11. constexpr int factorial(int n)
  12. {
  13.     // 지역 변수
  14.     int result = 0;
  15.  
  16.     // 여러 개의 반환문
  17.     if (<= 1)
  18.         result = 1;
  19.     else
  20.         result = n * factorial(- 1);
  21.  
  22.     return result;
  23. }

 

constexpr 함수는 컴파일러에게 가능하다면, 상수시간에 컴파일해 달라고 요청하는 것이지만 상황에 따라 컴파일 타임에 미리 실행될 수도 있고, 그렇지 못하고 런타임에 실행될 수도 있다.

(마치 inline 키워드가 그러하듯이 말이다)

 

constexpr의 함수 인자들이 constexpr 규칙에 부합하지 못하는 경우엔 컴파일 타임에 실행되지 못하고 런타임에 실행된다.

런타임 실행 여부는 여러 가지 방식으로 검증해 볼 수 있다.

  • breakpoint 걸어서 중단되는지 확인
  • 아래 예제의 constN 같은 테스팅 템플릿 작성
  • 정수일 경우 배열의 dimension으로 작성