momodudu.zip

#5 constexpr keyword 본문

C++

#5 constexpr keyword

ally10 2022. 8. 1. 12:05

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