momodudu.zip
#5 constexpr keyword 본문
c++11 부터 제공되는 상수 표현식 키워드.
상수 표현식은 변수나 함수, 생성자 등에 대해서도 컴파일 타임에 상수처럼 처리할 수 있게 해준다. 17부터는 람다도 상수 표현식 사용이 가능하다. constexpr이 붙은 변수, 또는 함수는 컴파일타임에 타입이 결정되는 Literal type에만 적용이 가능하다.
뭐가 리터럴 타입인지 헷갈린다면, 표준함수에서 제공하는 std::is_lateral_type을 사용하면 된다.
constexpr int getNumber()
{
return 10;
}
void main()
{
int myArray[getNumber()];
}
위와 같은 형태로, constexpr 키워드가 붙은 함수/변수는 컴파일타임에 타입이 상수표현식으로 결정이 되므로, 런타임에는 동적이 아니면 결정할 수 없는 array에 함수를 넣을수도 있다. 단, 이 경우 컴파일러는 int myArray[10]과 똑같이 해석한다는것에 유의해야한다.
이와 비슷한 기능을 하는것이 바로 inline함수인데, inline과 비슷하게 컴파일타임에 같이 컴파일된다.
c++14부터는 constexpr함수 내부의 지역변수 선언 및 if-else에 따른 리턴값을 다르게 주는것도 가능하다.
따라서 함수에 constexpr를 넣으면 상당히 많은 제약사항이 따른다. 뭔가 런타임에 결정된다 싶으면 다 안된다고 보면 된다.
- 함수 본문에 goto, try/catch, 초기화 하지 않은 변수, 리터럴 타입이 아닌 변수가 없어야 하고, exception을 던져서도 안되며, 다른 constexpr함수를 부를수도 없다.
- constexpr함수의 매개변수/리턴 타입이 반드시 리터럴 타입이어야 한다.
- 클래스의 멤버가 constexpr일땐 virtual로 선언할 수 없다.
- constexpr 구현 코드를 컴파일러가 해석하기 전까지는 호출할 수 없다. 즉, 코드 사용 순서에 영향을 받을 수 있다.
- dynamic cast, reinterpret_cast를 사용할 수 없다.
- new/delete를 사용할 수 없다.
직접 만든 클래스 타입을 constexpr로도 만들 수 있는데, 이때는 생성자를 constexp로 선언하면 된다.
class MyRect
{
public:
constexpr MyRect(size_t width, size_t height) :
mWidth(width), mHeight(height) = default;
constexpr size_t getArea { return mWidth * mHeight; }
private:
size_t mWidth, mHeight;
};
이에도 제약사항이 많이 따른다.
- virtual base class를 가질 수 없다.
- 생성자의 매개변수가 모두 리터럴 타입이다.
- 생성자 본문에 try block으로 만들 수 없다.
- 생성자 본문을 명시적으로 "default"로 선언하거나, 만약 default가 아니라면 위에서 설명한 constexpr 가 붙은 함수와 동일한 제약사항을 갖는다.
- 모든 데이터 멤버를 상수표현식으로 초기화해야한다.
const와의 차이점은, const는 변수 초기화를 런타임까지 지연시킬 수 있는데, constexpr의 경우에는 모두 컴파일타임에 이루어진다.
'C++' 카테고리의 다른 글
Generics - template instantiation, specialization (0) | 2022.11.22 |
---|---|
#4 std::uniform_int_distribution (0) | 2022.08.01 |
#3 Capturing variables in Lambda (0) | 2020.11.25 |
#2 C++ const keyword와 오버로딩에 관하여 (0) | 2019.10.01 |
#1 C++ STL Container (0) | 2019.08.28 |