티스토리 뷰

constexpr 은 객체에 적용했을때는 const 가 되며, 이 값은 컴파일 시점에 알려진다. 컴파일 시점에 알려지는 값들은 읽기 전용 메모리에 배치될 수 있다. 또 다른 장점으로는 컴파일 시점에 정수 상수 표현식이 요구되는 문맥에서 사용할 수 있다는 것이다. 어떤 경우에 사용할 수 있는지 예제를 통해 알아보자.

int sz;                                 // 비 constexpr 변수
...
constexpr auto arraySize1 = sz;         // error
std::array<int, sz> data1;              // error

constexpr auto arraySize2 = 10;         // 10은 상수
std::array<int, arraySize2> data2;      // arraySize2는 constexpr 객체

여기서 알아야할것은 constexpr 이 아닌 const 로 선언하였다면 컴파일에러가 발생한다. 그 이유는 컴파일 시점에 값이 알려지지 않기 때문이다. 컴파일 시점 상수를 요구하는 문맥에 사용할 수 있다면 constexpr 이 아닌 const 를 사용해야한다.

함수에서의 constexpr

constexpr 은 객체에서가 아닌 함수에서 사용할 때  더 흥미로워진다. 예를들어 3^n 의 사이즈를 갖는 배열을 만들어야한다고 하자. 만약 컴파일 타임에 n 의 값을 알 수 있다면 컴파일 단계에서 배열의 사이즈를 잡는것이 유리할 것이다. 아래와 같이 작성이 가능하다.

constexpr
int pow(int base, int exp) noexcept
{
    ...
}

constexpr auto numConds = 5;
std::array<int, pow(3, numConds)> results;

함수 안의 내부 구현은 C++ 의 버젼에 따라 다르다. C++11 에서는 C++14 보다 강한 제약들이 존재한다. 

  • 실행 가능 문장은 많아야 하나이다. (한 줄이 최대이다.)
  • 보통의 경우 return 문일 수밖에 없다.

위의 조건들로 인해 우리는 if 문 조차 만들지 못한다. 그렇기에 우리는 삼항 연산자와 재귀를 사용해야만 한다.

constexpr int pow(int base, int exp) noexcept
{
    return (exp == 0 ? 1 : base * pow(base, exp - 1));
}

C++14에서는 이 제약이 느슨해져서, 다음과 같이 구현이 가능하다.

constexpr int pow(int base, int exp) noexcept
{
    auto result = 1;
    for (int i = 0; i < exp; ++i) result *= base;
    
    return result;
}

 

멤버 함수에서의 constexpr

constexpr 함수는 반드시 리터럴 형식들을 주고 받아야한다. C++11 에서는 void 를 제외한 모든 내장 형식이 리터럴 형식에 해당한다. 그리고 생성자와 몇몇 멤버 함수들이 constexpr 이 될 수 있다.

class Point {
public:
    constexpr Point(double xVal = 0, double yVal = 0) noexcept
    : x(xVal), y(yVal)
    {}
    
    constexpr double xValue() const noexcept { return x; }
    constexpr double yValue() const noexcept { return y; }
    
    void setX(double newX) noexcept { x = newX; }
    void setY(double newY) noexcept { y = newY; }
    
private:
    double x, y;
};

생성자가 constexpr 로 되어 있는것을 확인 할 수 있는데, 이것이 가능하려면 인수들이 컴파일 시점에 알려줄 수 있어야한다.

constexpr Point p1(9.4, 27.7);

constexpr Point p2(28.8, 5.3;

위의 클래스에서 setX setY constexpr 로 선언되어 있지 않은것을 알 수 있는데, 그 이유는 C++11 에서의 제약 때문이다.

  • constexpr 멤버 함수는 암묵적으로 const 로 선언된다. 따라서 멤버 변수를 수정할 수 없다.
  • 반환 형식이 void 인데, C++11 에서는 리터럴 형식이 아니다.

C++14 에서는 이 제약들이 사라져 setter 함수들도 constexpr 이 될 수 있다.

 

참고 서적

스콧 마이어스, Effective Modern C++

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함