Menu
Coddy logo textTech

constexpr와 consteval

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 87번째.

C++는 런타임이 아닌 컴파일 타임에 연산이 수행되도록 허용하며, 이는 성능을 크게 향상시킬 수 있습니다. constexpr 키워드(C++11)와 consteval 키워드(C++20)는 표현식이 평가되는 시점을 제어할 수 있게 해줍니다.

constexpr 함수는 상수 인자가 주어지면 컴파일 시간에 평가될 수 있지만, 상수가 아닌 입력이 주어지면 런타임에도 실행될 수 있습니다:

#include <iostream>

constexpr int square(int n) {
    return n * n;
}

int main() {
    constexpr int compileTime = square(5);  // 컴파일 시간에 평가됨
    
    int x = 7;
    int runtime = square(x);  // 런타임에 평가됨
    
    std::cout << compileTime << "\n";  // 25
    std::cout << runtime << "\n";      // 49
}

컴파일 시간 평가를 보장해야 할 때는 consteval을 사용하세요. consteval 함수는 반드시 상수를 생성해야 하며, 런타임 값으로 이를 호출하는 것은 컴파일 오류입니다:

consteval int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

int main() {
    constexpr int result = factorial(5);  // 성공: 120이 컴파일 시간에 계산됨
    
    // int x = 5;
    // int bad = factorial(x);  // 오류: x는 상수가 아님
}

또한 변수와 클래스 생성자에도 constexpr을 사용할 수 있어, 전체 객체를 컴파일 시간에 생성할 수 있습니다. 이는 룩업 테이블, 설정 값 또는 프로그램 실행 중에 변경되지 않는 모든 데이터에 특히 유용합니다.

challenge icon

챌린지

쉬움

코드를 세 개의 파일로 나누어 구성합니다:

  • MathUtils.h: 컴파일 타임 수학 함수를 정의합니다.

    다음 함수들을 생성하세요:

    • cubeint를 인자로 받아 그 세제곱(n * n * n)을 반환하는 constexpr 함수
    • triangularNumber — n * (n + 1) / 2 공식을 사용하여 n번째 삼각수를 계산하는 constexpr 함수. 이 함수는 항상 컴파일 타임에 평가되어야 합니다.
    • sumOfSquares — 두 개의 정수를 인자로 받아 그 제곱의 합(a*a + b*b)을 반환하는 constexpr 함수
  • Config.h: 컴파일 타임 상수를 사용하여 설정 구조체를 생성합니다.

    세 개의 정수 width, height, depth를 인자로 받는 constexpr 생성자를 가진 Config 구조체를 정의하세요. 이 값들을 public 멤버로 저장합니다. 또한 width * height * depth를 반환하는 volume()이라는 constexpr 메서드를 추가하세요.

    구조체 아래에 10, 20, 5 값으로 초기화된 DEFAULT_CONFIG라는 constexpr 전역 상수를 생성하세요.

  • main.cpp: 런타임 값을 나타내는 두 개의 정수를 입력받습니다.

    먼저, constexpr 변수를 생성하여 컴파일 타임 평가를 보여줍니다:

    • cube(4)를 constexpr 변수에 저장하고 출력합니다: Cube of 4: [value]
    • triangularNumber(10)을 constexpr 변수에 저장하고 출력합니다: 10th triangular number: [value]
    • 기본 설정의 부피를 출력합니다: Default volume: [value]

    그 다음, 입력받은 두 값을 사용하여 constexpr 함수가 런타임에도 작동할 수 있음을 보여줍니다:

    • 첫 번째 입력값으로 cube()를 호출하고 출력합니다: Cube of [input]: [result]
    • 두 입력값으로 sumOfSquares()를 호출하고 출력합니다: Sum of squares: [result]

예를 들어, 입력값이 34인 경우:

Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 3: 27
Sum of squares: 25

입력값이 512인 경우:

Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169

치트 시트

C++는 constexpr (C++11) 및 consteval (C++20) 키워드를 사용하여 컴파일 시간(compile time)에 연산을 수행할 수 있도록 허용합니다.

constexpr 함수는 상수 인자와 함께 사용될 때 컴파일 시간에 평가될 있지만, 상수가 아닌 입력과 함께 사용될 때는 런타임에도 실행됩니다:

constexpr int square(int n) {
    return n * n;
}

constexpr int compileTime = square(5);  // 컴파일 시간에 평가됨

int x = 7;
int runtime = square(x);  // 런타임에 평가됨

consteval 함수는 반드시 컴파일 시간에 평가되어야 합니다. 런타임 값으로 이 함수를 호출하면 컴파일 오류가 발생합니다:

consteval int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

constexpr int result = factorial(5);  // OK: 컴파일 시간에 계산됨

// int x = 5;
// int bad = factorial(x);  // 오류: x는 상수가 아님

변수, 클래스 생성자, 메서드에 constexpr을 사용하여 컴파일 시간 객체 생성을 활성화할 수 있습니다:

struct Config {
    int width, height, depth;
    
    constexpr Config(int w, int h, int d) 
        : width(w), height(h), depth(d) {}
    
    constexpr int volume() const {
        return width * height * depth;
    }
};

constexpr Config config(10, 20, 5);  // 컴파일 시간에 생성됨

직접 해보기

#include <iostream>
#include "MathUtils.h"
#include "Config.h"

using namespace std;

int main() {
    // 입력으로부터 두 개의 정수 읽기
    int input1, input2;
    cin >> input1;
    cin >> input2;
    
    // TODO: 컴파일 타임 평가 시연
    // cube(4)를 저장하는 constexpr 변수를 생성하고 "Cube of 4: [value]"를 출력
    
    // TODO: triangularNumber(10)을 저장하는 constexpr 변수 생성
    // 그리고 "10th triangular number: [value]"를 출력
    
    // TODO: 기본 설정의 볼륨 출력: "Default volume: [value]"
    
    // TODO: constexpr 함수의 런타임 사용 시연
    // input1으로 cube()를 호출하고 "Cube of [input1]: [result]"를 출력
    
    // TODO: 두 입력값으로 sumOfSquares() 호출
    // 그리고 "Sum of squares: [result]"를 출력
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨