C++ 문법 정리 - 5 constexpr
문법 정리
constexpr
c++11에 새롭게 도입되었고 점차 발전되고 있는 키워드이다.
쉽게 말하자면 컴파일 시간에 정의될 수 있는 상수를 연산을 통해 정의할 수 있다고 생각할 수 있다.
변수와 함수 모두에 사용할 수 있다.
이는 템플릿 메타프로그램에도 잘 어울린다.
const ll mod = 1e9 + 7;
constexpr inline ll md(ll m, ll x) { return x >= 0 && x < m ? x : (x %= m) < 0 ? x + m : x; }
constexpr inline ll md(ll x) { return md(mod, x); }
constexpr ll Factorial(int n) {
ll total = 1;
for (int i = 1; i <= n; i++) {
total = md(total * i);
}
return total;
}
template<int N>
struct A {
int operator()() { return N; }
};
int main() {
fastio;
A<Factorial(100000)> a;
std::cout << a() << endl;
}
constexpr
함수의 제약
goto
- 리터럴 타입이 아닌 변수 정의
- 초기화 되지 않은 변수 정의
- 실행 중간에
constexpr
이 아닌 함수 호출
이 행위들은 불가능하다.
constexpr
생성자
생성자를 constexpr
을 붙여서 정의할 수 있고 위에서의 제약을 모두 따른다.
또한, 해당 클래스는 다른 클래스를 virtual
상속받을 수 없다.
class A {
public:
int a, b;
constexpr A(int a, int b) : a(a), b(b) {}
};
int main() {
constexpr A a{1, 2};
cout << a.a;
return 0;
}
if constexpr
템플릿 타입을 constexpr
로 검사할 수 있는 아름다운 방법이 있다.
이제 type_traits
헤더의 것들에서 TMP를 써서 만들어진 유틸리티 함수들을 사용할 수 있다. is_integral
, is_pointer
등 여러가지가 있다.
template<typename T>
void fn(T a) {
if constexpr (std::is_integral<T>::value) {
cout << "integer\n";
} else if constexpr (std::is_pointer<T>::value) {
cout << "pointer \n";
} else {
cout << "not integer\n";
}
}
int main() {
fn(1);
fn(1.1);
int *a = new int(5);
fn(a);
return 0;
}
integer
not integer
pointer
is_integral<T>::value
처럼 해야하는 것을 c++17에 등장한 value
를 바로 가져와주는 is_integral_v<T>
를 쓸 수도 있다.
하지만 constexpr
을 붙이지 않아도 위 코드는 런타임에라도 타입 검사를 할 수는 있는데, constexpr
을 붙이면 저 안에서 항상 저 타입이란게 컴파일 타임에 보장이 되어서 관련된 연산을 할 수 있거나 사용성이 높아진다.
c++20
std::vector
, std::string
이나 여러 stl
의 알고리즘들도 constexpr
이 가능해졌다.
const
vs constexpr
const
는 값이 불변이라는 것을 나타내고 컴파일 타임에 상수여야 할 필요는 없지만 constexpr
는 항상 컴파일 타임에 상수여야한다.
Comments