C++ 에는 constexpr 이라는 예약어가 있다.
보통 학생들은 잘 모르는 예약어인데, 왜냐면 딱히 이것까지 가르칠 필요는 없기 때문이랄까...
constexpr 에 대한 간단한 예시를 들면 다음과 같은 것이 있다.
1
2
3
|
int cc = 10;
const int a = cc; // OK
constexpr int b = cc; // Fail
|
cs |
보면 알겠지만 const 키워드는 runtime 에 결정되도 상관이 없는 반면
constexpr 의 경우는 반드시 compile 시간에 결정되어야 한다는 차이점이 있다.
때문에 나는 모두의 코드 블로그 에서 예제로 constexpr 을 사용하는것을 참조해 왔는데 다음과 같은 코드이다.
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
32
33
34
35
|
#include <iostream>
class Vector {
public:
constexpr Vector(int x, int y) : x_(x), y_(y) {}
constexpr int x() const { return x_; }
constexpr int y() const { return y_; }
private:
int x_;
int y_;
};
constexpr Vector AddVec(const Vector& v1, const Vector& v2) {
return { v1.x() + v2.x(), v1.y() + v2.y() };
}
template <int N>
struct A {
int operator()() { return N; }
};
int main() {
constexpr Vector v1{ 1, 2 };
constexpr Vector v2{ 2, 3 };
// constexpr 객체의 constexpr 멤버 함수는 역시 constexpr!
A<v1.x()> a;
std::cout << a() << std::endl;
// AddVec 역시 constexpr 을 리턴한다.
A<AddVec(v1, v2).x()> b;
std::cout << b() << std::endl;
}
|
cs |
코드를 면밀히 살펴보면 constexpr 예약어가 얼마나 유용하게 쓰일 수 있는지 알 수 있다.
해당 코드를 사용함으로써 원래 상수식이 들어가야만 했던 templeate 나,
배열의 동적할당 Size 를 정해주는등의 행위에 '변수' 를 집어넣을 수 있다.
물론 그것이 변경할 수 없는 상수라는점에서는 '리터럴' 과 큰 차이는 없지만
하나의 변수로 관리할 수있다는 점에서 큰 차이가 있다.
이게 의미하는점은 반드시 고정된 상수가 시작지점에 위치하여야 한다는 것이다.
사용자로부터 배열의 동적할당 크기를 입력받는 등의 행위는 여전히 불가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include <iostream>
using namespace std;
int main()
{
int a;
cin >> a;
if (a == 0)
{
constexpr int b = 0;
int* c = new int[b];
}
else
{
constexpr int b = 1;
int* c = new int[b];
}
}
|
cs |
뭐 어거지로 이따구로 쓸 순 있겠지만 블록 내에서 변수가 선언되었기 때문에 블록 밖에선 초기화 된다.
만약 블록 내에서만 처리하고 출력해야될 일이 있다면 사용할 순 있겠지만....
굳이..? 이딴식으로 코딩하면 죽일거다.
결국 constexpr 의 의의는,
같은 크기의 숫자로 선언된 10개의 배열의 관여된 코드를 수정할때 10개 모두를 일일이 수정하는 대신
constexpr 로 선언된 변수를 이용해 해당 변수 하나만을 수정하여서 10개 모두를 바꾸는것이다.
위 코드에서 주의할 점이라면
생성자를 constexpr 로 선언해 줘야지만 → 멤버함수도 constexpr 로 사용이 가능하다는 점이다.
이는 생성자가 무엇인지 생각하면 쉽게 이해가 가능한데,
생성자는 해당 객체의 '초기화' 이다. 해당 객체를 내가 컴파일 시간에 확정되는 상수로 선언한다고 하면
해당 객체는 constexpr 로 선언되는것이다.
그리고 만약 멤버 함수가 constexpr 이라면 해당 함수의 리턴값을 templeate 이나,
배열의 동적할당 size로 지정해 주는것이 가능한 것이다.
즉
1
2
|
int* aaa = new int[v1.x()];
|
cs |
이런짓이 가능하다.
별것 아닌것 같으면서도 유용한것이 constexpr 예약어이므로 반드시 기억해 두도록 하자.
'Programming > C++' 카테고리의 다른 글
[C++] push_back vs emplace_back 차이점 (2) | 2020.12.07 |
---|---|
[C++] C4819 Warning 해결 방법, 한글 깨짐 문제 (0) | 2020.12.03 |
[C++] 함수 포인터 (0) | 2020.11.01 |
[C++] C++ 이 끔찍한 언어라 욕을 먹는 이유. (0) | 2020.09.30 |
[C++] system, WinExec 함수 출력값 받는법. (0) | 2020.08.17 |