const와 constexpr을 함께 쓴다는 건 어떤 의미일까?

constexpr const char*

cppreference에 따르면..

A constexpr specifier used in an object declaration or non-static member function (until C++14) implies const.

이므로

1
constexpr const int a = 3;

이는 다음과 동일하다

1
constexpr int a = 3;

그럼 constexpr와 const 둘 모두를 쓰는 경우는 그저 중복일 뿐이지, 의미는 없다.

그러나 몇몇 예제를 보면 가끔 constexpr const라는 표현이 존재한다. 왜 const를 더 썼을까?

cppreference/const_exp의 다음 소스를 보자.

1
2
3
4
5
6
7
8
9
void test() {
    static const int a = std::random_device{}();
    constexpr const int& ra = a; // OK: a is a glvalue constant expression
    constexpr int ia = a; // Error: a is not a prvalue constant expression
 
    const int b = 42;
    constexpr const int& rb = b; // Error: b is not a glvalue constant expression
    constexpr int ib = b; // OK: b is a prvalue constant expression
}

이때 constexpr이 들어간 표현만 보면

1
constexpr const int& ra = a;

이다.

사실 저 변수 정의에서 const 를 뺀

1
constexpr int& ra = a;

는 compile-time 상수라는 조건을 빼면

1
int& ra = a;

이라는 의미이지

1
const int& ra = a;

와는 전혀 다르다.

즉, constexpr 지정자의 대상은 타입이 아니라 변수 자체이다. 그러나 타입에 대한 const를 부여하기 때문에, 헷갈리게 하는것이다.

마찬가지로,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static size_t sz = sizeof(constexpr int); // 오류, constexpr int는 타입이 아닙니다.

constexpr char* str = "Hello"; // 오류: "Hello"를 char *로 캐스팅 할 수 없습니다.
constexpr const char* str = "Hello"; // 정상

static int a = 0;
constexpr int& ra = a; // 정상

static const int b = 0;
constexpr int& rb = b; // 오류, const int를 int&로 캐스팅 할 수 없습니다.

class T;
const T f();
constexpr T (*pf) = f; // 오류: const T()를 T(*)()로 캐스팅
constexpr const T (*pf) = f; // 정상

결론

  • constconstexpr이 같이 지정되어도 constexpr하나와 같다.
  • constexpr 지정자specifier의 대상은 type이 아니라 변수 자체이다.