개인 프로젝트를 하면서 constexpr을 알게 되었다. const와 constexpr 차이는 이해했다. 하지만 const만으로도 충분해 보이는데, 왜 굳이 constexpr가 필요한 건지 궁금했다. 정보를 찾은 결과를 이 글에 남겨보고자 한다.
값을 변경할 수 없다는 약속을 컴파일러에게 하는 키워드다.
한 번 초기화된 후에는 그 값을 바꿀 수 없다.
const int MAX_USERS = 100;
MAX_USERS = 200; // 컴파일 에러!
특징
int A;
std::cin >> A;
const int B = A; // 가능
// 상수 B는 런타임에 결정되지만, 이후 변경은 불가하다.
// 컴파일 타임에 값을 몰라도 되지만, 한 번 정해지면 변경할 수 없다.
const int* ptr1; // 가리키는 값을 바꿀 수 없음
int* const ptr2; // 포인터 자체를 바꿀 수 없음
const int* const ptr3; // 둘 다 바꿀 수 없음
class User {
private:
std::string name;
int age;
public:
// 멤버 변수를 수정하지 않음
std::string getName() const {
return name;
// age = 30; // 에러 발생
}
void setAge(int newAge) {
age = newAge; // 가능
}
};
한계
mutable로 선언하면 const 멤버 함수에서도 수정할 수 있다.const_cast로 const를 강제로 제거할 수 있다.constexpr은 constant expression의 약자로,
const와 달리 컴파일 타임에 반드시 결정된다는 보장을 컴파일러에게 하는 키워드다.
C++11에서 처음 등장했고 버전 업을 거치면서 대부분의 제약이 풀렸다.
constexpr int func(int n) {
return n * n;
}
constexpr int A = 1; // 컴파일 타임에 1로 초기화된다.
constexpr int B = func(2); // 컴파일 타임에 4로 계산된다.
constexpr int C = func(B); // 컴파일 타임에 16로 계산된다.
const와 결정적 차이는 아래와 같다:
int func() {
int value;
std::cin >> value;
return value;
}
const int a = func(); // 가능 -> 런타임에 결정되기 때문
constexpr int b = func(); // 에러 발생
사용 이유
// 1. 성능 향상
constexpr int factorial(int n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
constexpr int result = factorial(10); // 실행 시 계산 비용 0
// 2. 배열 크기
constexpr int SIZE = 100;
int buffer[SIZE]; // OK
const int size = getSize();
int arr[size]; // 대부분 에러
// 3. 컴파일 타임 검증
constexpr int divide(int a, int b) {
return b == 0 ? throw "error" : a / b;
}
constexpr int x = divide(10, 0); // 컴파일 에러 발생
const를 사용하는 경우
const를 사용한다.const로 선언한다.constexpr을 사용하는 경우
switch문의 case 레이블, static_assert 등에서 사용한다.| 상황 | const | constexpr |
|---|---|---|
| 사용자 입력값 | O | X |
| 배열 크기 | △ | O |
| 템플릿 인자 | X | O |
| 함수 파라미터 | O | X |
| 컴파일 타임 계산 | △ | O |
const는 변경 불가의 약속이고, constexpr는 컴파일 타임 계산의 보장이다.
const는 런타임 값도 받을 수 있지만, constexpr는 오직 컴파일 타임에만 결정된다.