티스토리 뷰
[Effective Modern C++] 항목 15. 가능하면 항상 constexpr을 사용하라
pppgod 2019. 10. 29. 00:07constexpr 은 객체에 적용했을때는 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++
'C++ > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 항목 17. 특수 멤버 함수들의 자동 작성 조건을 숙지하라 (0) | 2019.11.02 |
---|---|
[Effective Modern C++] 항목 16. const 멤버 함수를 스레드에 안전하게 작성하라 (0) | 2019.10.30 |
[Effective Modern C++] 항목 14. 예외를 방출하지 않을 함수는 noexcept로 선언하라 (0) | 2019.10.20 |
[Effective Modern C++] 항목 13. iterator보다 const_iterator를 선호하라 (0) | 2019.10.20 |
[Effective Modern C++] 항목 12. 재정의 함수들을 override로 선언하라 (0) | 2019.10.07 |
- Total
- Today
- Yesterday
- 다이소
- C
- C++14
- 포인터
- Perfect
- auto
- Join
- C++11
- Effective
- std::move
- Future
- MOVE
- 발아시기
- async
- detach
- Unreal
- C++
- Override
- forward
- 보편 참조
- Forwarding
- Modern
- Effective Modern C++
- Overloading
- CPP
- const
- thread
- 보편참조
- 람다
- std::forward
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |