1. constexpr
- 객체나 함수 앞에 붙일 수 있음
- 해당 객체나 함수의 리턴값을 컴파일 타임에 알 수 있다는 의미
- 상수식: 컴파일러가 컴파일 타임에 어떠한 식의 값을 결정할 수 있는 것
#include <iostream>
template <int N>
struct A {
int operator()() { return N; }
};
int main() {
constexpr int size = 3;
int arr[size]; // Good!
constexpr int N = 10;
A<N> a; // Good!
std::cout << a() << std::endl;
constexpr int number = 3;
enum B { x = number, y, z }; // Good!
std::cout << B::x << std::endl;
}
2. const와의 차이점
const
로 정의된 상수들을 굳이 컴파일 타임에 그 값을 알 필요가 없음
constexpr
은 오른쪽에 상수식이 와야함
- 컴파일 타임에 상수를 확실히 사용하고 싶다면
constexpr
키워드 사용을 지향
3. constexpr함수
constexpr
을 사용하지 않는다면 메타프로그래밍을 사용해야 함
- 제약조건
goto
문 사용
- 예외 처리
- 리터럴 타입이 아닌 변수의 정의
- 초기화 되지 않는 변수의 정의
- 실행 중간에
constexpr
이 아닌 함수 호출
#include <iostream>
constexpr int Factorial(int n) {
int total = 1;
for (int i = 1; i <= n; i++) {
total *= i;
}
return total;
}
int main() {
int num;
std::cin >> num;
std::cout << Factorial(num) << std::endl;
}
4. constexpr 생성자
- 일반적인 constexpr 함수에서 적용되는 제약조건들 모두 적용
- 인자들이 반드시 리터럴 타입
- 해당 클래스는 다른 클래스를 가상 상속 받을 수 없음
#include <iostream>
class Vector {
public:
constexpr Vector(int x, int y) : x_(x), y_(y) {}
constexpr int x() const { return x_; }
constexpr int y() const { return y_; }
private:
int x_;
int y_;
};
constexpr Vector AddVec(const Vector& v1, const Vector& v2) {
return {v1.x() + v2.x(), v1.y() + v2.y()};
}
template <int N>
struct A {
int operator()() { return N; }
};
int main() {
constexpr Vector v1{1, 2};
constexpr Vector v2{2, 3};
// constexpr 객체의 constexpr 멤버 함수는 역시 constexpr!
A<v1.x()> a;
std::cout << a() << std::endl;
// AddVec 역시 constexpr 을 리턴한다.
A<AddVec(v1, v2).x()> b;
std::cout << b() << std::endl;
}
5. if constexpr
- 타입에 따라 형태가 달라지는 함수의 경우 사용 가능
- 제약 조건
bool
로 타입 변환될 수 있어야 하는 컴파일 타임 상수식이어야 함
- 예시 코드
#include <iostream>
#include <type_traits>
template <typename T>
void show_value(T t) {
if constexpr (std::is_pointer<T>::value) {
std::cout << "포인터 이다 : " << *t << std::endl;
} else {
std::cout << "포인터가 아니다 : " << t << std::endl;
}
}
int main() {
int x = 3;
show_value(x);
int* p = &x;
show_value(p);
}