일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 오블완
- lua
- effective stl
- Smart Pointer
- universal reference
- 게임
- reference
- iterator
- 상속
- 영화 리뷰
- effective modern c++
- exception
- more effective c++
- 반복자
- 참조자
- virtual function
- c++
- std::async
- 티스토리챌린지
- 보편 참조
- 예외
- Effective c++
- 암시적 변환
- resource management class
- 스마트 포인터
- 언리얼
- 영화
- UE4
- implicit conversion
- operator new
Archives
- Today
- Total
스토리텔링 개발자
[Effective Modern C++] 15. constexpr 본문
728x90
항목 15. 가능하면 항상 constexpr을 사용하라
constexpr 개요
- 객체에 적용하면 const의 강화된 버전처럼 작용한다.
- 어떠한 값이 상수인데다 컴파일 시점에 알려지게 한다.
- 허나 함수에 적용하면 상당히 다른 의미로 작용한다.
- 결과값이 반드시 const가 아니다.
- 심지어 반드시 컴파일 시점에 알려진다는 보장도 없다.
- 결함이 아닌 의도된 기능이다.(심지어 위 두 성질은 constexpr의 장점이다.)
constexpr 객체
- constexpr 객체는 실제로 const이며, 그 값은 실제로 컴파일 시점에 알려진다.
- 컴파일 시점에 알려지는 값에는 특별한 권한이 있다.
- 읽기 전용 메모리에 배치될 수 있다.
- C++에서 정수 상수 표현식(integral constant expression)이 요구되는 문맥에서 사용할 수 있다.
- 배열 크기
- 정수 템플릿 인수
- 열거자 값
- allignment 지정자
int sz;
...
constexpr auto arraySize1 = sz; // 에러! sz의 값은 컴파일에 확정적이지 않다.
std::array<int, sz> data1; // 여전히 에러!
constexpr auto arraySize2 = 10; // 성공
std::array<int, arraySize2> data2; // constexpr 객체를 사용하므로 성공
// const를 사용한다면?
const auto arraySize = sz; // 성공
std::array<int, arraySize> data; // 에러! const 객체는 컴파일 시점에 확정되는 값이 아니다.
constexpr 함수
- 컴파일 시점 상수를 매개변수로 호출하면 컴파일 시점 상수를 리턴한다.
- 컴파일 시점 상수를 요구하는 문맥에 constexpr 함수를 사용할 수 있다.
- 다만 매개변수의 값이 컴파일 시점에 확정적이지 않으면 컴파일 에러.
- 런타임 시점의 수를 매개변수로 호출하면 런타임 시점 값을 리턴한다.
- 컴파일 시점에 확정되지 않는 수를 하나라도 사용하면 보통의 함수처럼 동작한다.
- 즉, 컴파일 시점용, 런타임 시점용 함수를 두 가지 나눠서 구현하지 않아도 된다!
constexpr
int pow(int base, int exp) noexcept
{
...
}
constexpr auto numConds = 5;
std::array<int, pow(3, numConds)> results; // 컴파일 시점용으로 사용
// constexpr 객체를 인자로 pow 를 호출하였으므로
// 리턴되는 값은 컴파일 시점에 확정적이다.
auto base = readFromDB("base");
auto exp = readFromDB("exponent");
auto baseToExp = pow(base, exp); // 런타임 시점용으로 사용
- constexpr 함수 구현의 제약
- C++11과 C++14의 제약들이 조금 다르다.
- C++11
- 실행 가능 문장이 하나를 넘으면 안된다.
- 즉, return 문 하나만 사용할 수 있다.
- 조건부 연산자(삼항 연산자)와 재귀를 사용하여 이 제약을 해소할 수 있을 것이다.
-
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; }
- 반드시 리터럴 타입(literal type)들을 받고 돌려줘야 한다.
- 리터럴 타입
- 컴파일 도중에 값을 결정할 수 있는 타입.
- 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.2); // 성공
constexpr Point p2(28.8, 5.3); // 역시 성공
// getter 함수 역시 constexpr이므로
// 이 함수를 호출하는 또 다른 constexpr 함수를 선언하는 것도 가능하다.
constexpr
Point minpoint(const Point& p1, const Point& p2) noexcept
{
return { (p1.xValue() + p2.xValue()) / 2,
(p1.yValue() + p2.yValue()) / 2 };
}
constexpr auto mid = midpoint(p1, p2);
- C++11에서는 두 가지 제약 때문에 Point의 멤버 함수 setX, setY를 constexpr로 선언할 수 없다.
- 멤버 함수들은 작동 대상 객체를 수정하는데, C++11에서는 constexpr 멤버 함수는 암묵적으로 const이다.
- 이 멤버 함수들은 리턴 타입이 void인데, C++11에서는 void가 리터럴 타입이 아니다.
- 하지만 C++14에서는 위 두 제약이 사라졌으므로 setter도 constexpr로 선언할 수 있다.
class Point
{
public:
...
constexpr void setX(double newX) noexcept { x = newX; } // C++14
constexpr void setY(double newY) noexcept { y = newY; } // C++14
...
};
// 그럼 이제 아래와 같은 함수를 작성할 수도 있다.
constexpr Point reflection(const Point& p) noexcept
{
Point result;
result.setX(-p.xValue());
result.setY(-p.yValue());
return result;
}
constexpr Point p1(9.4, 27.7);
constexpr Point p2(28.8, 5.3);
constexpr auto mid = midpoint(p1, p2);
constexpr auto reflectedMid = reflection(mid); // 성공
728x90
'Effective C++ > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 17. 특수 멤버 함수(special member function) (1) | 2025.02.27 |
---|---|
[Effective Modern C++] 16. thread safety한 const 멤버 함수 (0) | 2025.02.26 |
[Effective Modern C++] 14. noexcept (0) | 2025.02.24 |
[Effective Modern C++] 13. const_iterator 선호하기 (0) | 2025.02.21 |
[Effective Modern C++] 12. override 키워드와 참조 한정사(reference qualifier) (0) | 2025.02.20 |
Comments