이펙티브 모던 C++의 항목 15에서
가능하면 항상 constexpr을 사용하라
라는 조언이 있는데, 읽으면서 예제를 따라해보다가 constexpr이 생각보다 컴파일이 잘 안되는 것 같아 블로그에 정리해서 공부해보려고 한다
C++11에 새롭게 도입된 객체나 함수 앞에 붙일 수 있는 키워드로, 해당 객체나 함수의 리턴값을 컴파일 타임에 값을 알 수 있다라는 의미를 지니게 된다.
컴파일이란
개발자가 작성한 프로그램 소스 코드가 컴파일러에 의해 실행될 수 있는 기계 코드로 변환되는 과정
이며 이런 컴파일을 진행하는 과정을 컴파일 타임이라고 한다
반면 런타임은
컴파일 과정을 마친 프로그램이 실제로 실행되는 시간을 말한다
컴파일 타임에서 에러가 나는 경우는 컴파일러가 프로그램을 컴파일 하지 못해 실행이 안되며
런타임에서 에러가 나는 경우는 프로그램이 실행은 됐는데 버그로 인해 실행이 종료되는 현상이다
본론으로 돌아가서 컴파일러가 컴파일 타임에 어떤 표현식의 값을 결정할 수 있다면 해당 식을 상수식이라고 하며 상수식들 중 값이 정수인 것을 정수 상수식이라고 한다.
정수 상수식이 필요한 경우
1. int arr[size]같은 배열 선언식이 컴파일 되기 위해서
2. 템플릿 타입 인자의 경우
3. enum에 값을 지정해줄 경우
constexpr은 어떠한 식이 상수식이라고 명시해주는 키워드이다. 객체 앞에 붙여 선언한다면 이 객체는 상수식에 사용할 수 있음
#include <iostream>
int main()
{
int size = 6;
constexpr int csize = 5;
int arr[size]; // 컴파일 X
int arr2[csize]; // 컴파일 OK
}
그런데 이미 우리는 constexpr과 비슷한 const에 대해 잘 알고 있을 텐데 둘이 무엇이 다른건가??
const로 정의된 상수들은 굳이 컴파일 타임에 그 값을 알 필요가 없음
int a;
...
const int ca = a;
a의 값을 모르더라도 위의 코드는 컴파일되며 a의 값이 정해지면 ca는 수정할 수 없는 값이 된다
반면 constexpr의 경우 반드시 다른 상수식이 와야 하는데
int a;
...
constexpr cea = a; // X
여기서는 컴파일러가 컴파일 타임에 a가 무엇이 올 지 알 수 없다. 그래서 컴파일 오류가 나버림
정리해보면 constexpr은 항상 const이지만, const는 constexpr이 아니다를 기억해두자. 그래서 이펙티브 모던 c++에서도 가능한 항상 constexpr을 사용하라고 명시해뒀다
객체에 constexpr을 사용하면 해당 객체는 컴파일 타임에 상수로 결정된다고 했는데 함수에 쓰면 컴파일 타임 상수를 산출하는 함수를 만들어낼 수 있지 않을까??
결론은 만들 수 있다이다.
int sum(int x, int y)
{
return x + y;
}
int main()
{
constexpr int sum1 = sum(3,4); // 컴파일 에러!
}
현재 sum 함수는 런타임 값을 산출하므로 constexpr 변수를 컴파일하지 못한다.
그러나 sum 함수 앞에 constexpr을 추가해주면
constexpr int sum(int x, int y)
{
return x + y;
}
int main()
{
constexpr int sum1 = sum(3,4); // OK
}
컴파일이 잘되어 sum1은 컴파일 타임에 계산된다
C++11에서 constexpr이 처음 도입되었을 때는 제약이 많았다
그러나 C++14에 와서 제약 조건들이 완화되어 아래의 제약 조건 빼고는 모두 가능해짐
goto문try문; C++20부터 가능해짐)constexpr이 아닌 함수를 호출참고로 함수 앞에 constexpr를 지정해도 컴파일 타임 상수가 아닌 일반 값을 전달했다면 그 함수는 일반 함수철머 동작하게 된다
이외에도 constexpr 생성자나 다른 내용들이 있지만 간단한 개념 정리이므로 여기까지만 블로그에 정리하고 나머지는 참고한 블로그를 정독했다