ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄/C++ μ‘μš©

[c++] constexpr의 λͺ¨λ“  것

μ„œμ•„λž‘πŸ˜ 2024. 8. 21. 23:15

바닀와 같이 항상성을 μœ μ§€ν•˜λŠ” constexpr

 

 

constexprλŠ” C++11μ—μ„œ λ„μž…λœ ν‚€μ›Œλ“œλ‘œ, 컴파일 νƒ€μž„μ— 계산이 κ°€λŠ₯ν•œ μƒμˆ˜ ν‘œν˜„μ‹μ„ μ •μ˜ν•  수 있게 ν•΄μ€λ‹ˆλ‹€. 이 ν‚€μ›Œλ“œλŠ” 주둜 ν•¨μˆ˜λ‚˜ λ³€μˆ˜λ₯Ό 컴파일 νƒ€μž„μ— ν‰κ°€ν•˜μ—¬ ν”„λ‘œκ·Έλž¨μ˜ νš¨μœ¨μ„±μ„ λ†’μ΄λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. C++17 μ΄ν›„λ‘œλŠ” μ‚¬μš© λ²”μœ„κ°€ λ”μš± ν™•μž₯λ˜μ–΄ ν•¨μˆ˜μ™€ λ³€μˆ˜λΏλ§Œ μ•„λ‹ˆλΌ λ³΅μž‘ν•œ μ—°μ‚°κ³Ό 쑰건문을 ν¬ν•¨ν•œ λ‹€μ–‘ν•œ ν‘œν˜„μ‹λ„ 컴파일 νƒ€μž„μ— 계산할 수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

constexpr의 νŠΉμ§• 및 μ‚¬μš© 방법

1. constexpr λ³€μˆ˜

constexpr λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ κ·Έ 값이 컴파일 νƒ€μž„μ— κ²°μ •λ˜λ„λ‘ 보μž₯λ©λ‹ˆλ‹€.

constexpr int myValue = 10; // 컴파일 νƒ€μž„μ— myValueλŠ” 10으둜 고정됨

2. constexpr ν•¨μˆ˜

constexpr ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ ν•΄λ‹Ή ν•¨μˆ˜κ°€ 컴파일 νƒ€μž„μ— ν˜ΈμΆœλ˜μ–΄ κ·Έ κ²°κ³Όκ°€ μƒμˆ˜λ‘œ μ‚¬μš©λ  수 μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜λŠ” λ°˜λ“œμ‹œ λ‹¨μˆœν•˜κ³ , λ³΅μž‘ν•œ λŸ°νƒ€μž„ 연산이 μ—†μ–΄μ•Ό ν•©λ‹ˆλ‹€.

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

이 ν•¨μˆ˜λŠ” 컴파일 νƒ€μž„μ— 계산할 수 μžˆλŠ” λͺ¨λ“  ν‘œν˜„μ‹μ— λŒ€ν•΄ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

constexpr int squaredValue = square(5); // 컴파일 νƒ€μž„μ— 25둜 계산됨

3. constexpr과 const의 차이점

  • constλŠ” λŸ°νƒ€μž„ μƒμˆ˜μž„μ„ μ˜λ―Έν•©λ‹ˆλ‹€. 즉, 컴파일 νƒ€μž„μ— λ°˜λ“œμ‹œ μ΄ˆκΈ°ν™”λ˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.
  • constexprλŠ” 컴파일 νƒ€μž„μ— λ°˜λ“œμ‹œ κ³„μ‚°λ˜μ–΄μ•Ό ν•˜λŠ” μƒμˆ˜ ν‘œν˜„μ‹μ„ μ˜λ―Έν•©λ‹ˆλ‹€.
const int runtimeValue = 10;         // λŸ°νƒ€μž„ μƒμˆ˜
constexpr int compileTimeValue = 20; // 컴파일 νƒ€μž„ μƒμˆ˜

constexpr ν•¨μˆ˜μ˜ 예제

기본적인 constexpr ν•¨μˆ˜

#include <iostream>

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

int main() {
    constexpr int result = factorial(5); // 컴파일 νƒ€μž„μ— 계산됨
    std::cout << "Factorial of 5: " << result << std::endl; // 좜λ ₯: Factorial of 5: 120
    return 0;
}

이 μ˜ˆμ œμ—μ„œλŠ” factorial ν•¨μˆ˜κ°€ 컴파일 νƒ€μž„μ— κ³„μ‚°λ˜μ–΄, resultκ°€ ν”„λ‘œκ·Έλž¨μ΄ μ‹€ν–‰λ˜κΈ° 전에 이미 120으둜 ν™•μ •λ©λ‹ˆλ‹€.

쑰건문을 ν¬ν•¨ν•œ constexpr ν•¨μˆ˜

C++14λΆ€ν„°λŠ” if, switch와 같은 쑰건문도 constexpr ν•¨μˆ˜ λ‚΄μ—μ„œ μ‚¬μš©ν•  수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

#include <iostream>

constexpr int max(int a, int b) {
    return (a > b) ? a : b;
}

int main() {
    constexpr int maxValue = max(10, 20); // 컴파일 νƒ€μž„μ— 20으둜 계산됨
    std::cout << "Max value: " << maxValue << std::endl; // 좜λ ₯: Max value: 20
    return 0;
}

constexpr와 C++ ν‘œμ€€μ˜ λ°œμ „

  • C++11: constexpr의 λ„μž…μœΌλ‘œ 컴파일 νƒ€μž„ μƒμˆ˜ ν‘œν˜„μ‹κ³Ό ν•¨μˆ˜λ₯Ό μ •μ˜ν•  수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜ λ‚΄μ—μ„œ 단일 return 문만 μ‚¬μš© κ°€λŠ₯ν–ˆμŠ΅λ‹ˆλ‹€.
  • C++14: constexpr ν•¨μˆ˜ λ‚΄μ—μ„œ 쑰건문 (if, switch), 반볡문 (for, while) 등을 μ‚¬μš©ν•  수 있게 λ˜μ–΄ 더 λ³΅μž‘ν•œ 계산이 κ°€λŠ₯ν•΄μ‘ŒμŠ΅λ‹ˆλ‹€.
  • C++17: constexpr의 적용 λ²”μœ„κ°€ λ”μš± ν™•μž₯λ˜μ–΄, constexpr μƒμ„±μžμ™€ 멀버 ν•¨μˆ˜, λ³΅μž‘ν•œ μ‚¬μš©μž μ •μ˜ νƒ€μž…μ— λŒ€ν•΄μ„œλ„ μ‚¬μš© κ°€λŠ₯ν•΄μ‘ŒμŠ΅λ‹ˆλ‹€.
  • C++20: constexprμ—μ„œλŠ” 더 λ§Žμ€ κΈ°λŠ₯듀이 ν¬ν•¨λ˜λ©°, 컴파일 νƒ€μž„ κ³„μ‚°μ˜ λ²”μœ„κ°€ 거의 λ¬΄ν•œλŒ€λ‘œ ν™•μž₯λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

 

 

 

constexpr ν•¨μˆ˜μ™€ inline ν•¨μˆ˜μ˜ 차이점

  • constexpr ν•¨μˆ˜:
    • 컴파일 νƒ€μž„μ— 계산될 수 μžˆλŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. constexpr ν•¨μˆ˜λŠ” 항상 컴파일 νƒ€μž„μ— κ³„μ‚°λ˜λ„λ‘ μš”κ΅¬λ˜λ©°, 이둜 인해 μƒμˆ˜ ν‘œν˜„μ‹μ˜ μΌλΆ€λ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • C++11λΆ€ν„° λ„μž…λ˜μ—ˆμœΌλ©°, μ»΄νŒŒμΌλŸ¬κ°€ κ²°κ³Όλ₯Ό 컴파일 νƒ€μž„μ— 평가할 수 μžˆλ„λ‘ 보μž₯ν•©λ‹ˆλ‹€.
    • 컴파일 νƒ€μž„μ— 평가될 수 μžˆλŠ” 경우, μ‹€μ œλ‘œ 컴파일 νƒ€μž„μ— κ³„μ‚°λ˜μ§€λ§Œ, λŸ°νƒ€μž„μ—μ„œλ„ 호좜될 수 μžˆμŠ΅λ‹ˆλ‹€.
  • inline ν•¨μˆ˜:
    • μ½”λ“œ 쀑볡을 쀄이기 μœ„ν•΄ ν•¨μˆ˜ ν˜ΈμΆœμ„ ν•¨μˆ˜ μ½”λ“œ 자체둜 λŒ€μ²΄ν•˜λ„λ‘ ν•˜λŠ” 힌트λ₯Ό μ»΄νŒŒμΌλŸ¬μ— μ œκ³΅ν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€.
    • inline ν‚€μ›Œλ“œλŠ” μ»΄νŒŒμΌλŸ¬μ—κ²Œ ν•¨μˆ˜λ₯Ό 인라인으둜 λŒ€μ²΄ν•΄λ‹¬λΌλŠ” μš”μ²­μ΄μ§€λ§Œ, μ‹€μ œλ‘œ 인라인으둜 λŒ€μ²΄ν• μ§€ μ—¬λΆ€λŠ” 컴파일러의 μž¬λŸ‰μ— 달렀 μžˆμŠ΅λ‹ˆλ‹€.
    • inline ν•¨μˆ˜λŠ” λŸ°νƒ€μž„μ— μ‚¬μš©λ©λ‹ˆλ‹€. λ”°λΌμ„œ 컴파일 νƒ€μž„μ— κ³„μ‚°λ˜μ§€λŠ” μ•ŠμœΌλ©°, 호좜될 λ•Œλ§ˆλ‹€ μ‹€ν–‰λ©λ‹ˆλ‹€.

μ˜ˆμ‹œ:

  • constexpr ν•¨μˆ˜:
constexpr int add(int x, int y) {
    return x + y;
}

int main() {
    constexpr int sum = add(3, 4);  // 컴파일 νƒ€μž„μ— 7둜 계산됨
    return 0;
}

 

  • inline ν•¨μˆ˜
inline int multiply(int x, int y) {
    return x * y;
}

int main() {
    int result = multiply(3, 4);  // λŸ°νƒ€μž„μ— 호좜됨
    return 0;
}

 

λ³΅μž‘ν•œ ν΄λž˜μŠ€λ‚˜ κ΅¬μ‘°μ²΄μ—μ„œ constexpr ν™œμš©

constexpr을 μ‚¬μš©ν•˜λŠ” 이유:

constexpr은 λ³΅μž‘ν•œ ν΄λž˜μŠ€λ‚˜ κ΅¬μ‘°μ²΄μ—μ„œλ„ 컴파일 νƒ€μž„μ— 객체λ₯Ό μ΄ˆκΈ°ν™”ν•˜κ±°λ‚˜ μƒμˆ˜λ₯Ό κ³„μ‚°ν•˜λŠ” 데 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” μ½”λ“œμ˜ νš¨μœ¨μ„±μ„ 높이고, νŠΉμ • 값듀이 컴파일 νƒ€μž„μ— κ³ μ •λ˜λ„λ‘ 보μž₯ν•˜μ—¬ 였λ₯˜ κ°€λŠ₯성을 μ€„μ΄λŠ” 데 μœ μš©ν•©λ‹ˆλ‹€.

μ‚¬μš© 방법:

  • constexpr μƒμ„±μž: 컴파일 νƒ€μž„μ— 객체λ₯Ό 생성할 수 μžˆλ„λ‘ ν—ˆμš©ν•©λ‹ˆλ‹€.
  • constexpr 멀버 ν•¨μˆ˜: 클래슀의 λ©”μ„œλ“œκ°€ 컴파일 νƒ€μž„μ— 호좜될 수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

μ˜ˆμ‹œ:

#include <iostream>

class Point {
public:
    constexpr Point(double x, double y) : x_(x), y_(y) {}

    constexpr double getX() const { return x_; }
    constexpr double getY() const { return y_; }

    constexpr double distanceToOrigin() const {
        return sqrt(x_ * x_ + y_ * y_);
    }

private:
    double x_;
    double y_;
};

int main() {
    constexpr Point p(3.0, 4.0);  // 컴파일 νƒ€μž„μ— 객체 생성
    constexpr double distance = p.distanceToOrigin();  // 컴파일 νƒ€μž„μ— 계산

    std::cout << "Distance to origin: " << distance << std::endl;  // 좜λ ₯: 5
    return 0;
}

 

constexpr을 μ‚¬μš©ν•  λ•Œ μ£Όμ˜ν•΄μ•Ό ν•  사항

μ£Όμ˜ν•  점:

  1. λ³΅μž‘ν•œ μ—°μ‚° μ œν•œ: λͺ¨λ“  연산이 컴파일 νƒ€μž„μ— 계산될 수 μžˆλŠ” 것은 μ•„λ‹™λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 파일 I/Oλ‚˜ 동적 λ©”λͺ¨λ¦¬ ν• λ‹Ή λ“±μ˜ 연산은 컴파일 νƒ€μž„μ— μˆ˜ν–‰λ  수 μ—†μŠ΅λ‹ˆλ‹€.
  2. ν•¨μˆ˜ λ‚΄ μƒνƒœ λ³€ν™” κΈˆμ§€: constexpr ν•¨μˆ˜ λ‚΄μ—μ„œλŠ” μƒνƒœλ₯Ό λ³€κ²½ν•  수 μ—†μŠ΅λ‹ˆλ‹€. λͺ¨λ“  μž…λ ₯이 κ·ΈλŒ€λ‘œ 좜λ ₯에 λ°˜μ˜λ˜μ–΄μ•Ό ν•˜λ©°, ν•¨μˆ˜ λ‚΄μ—μ„œ λ³€κ²½λ˜λŠ” κ°€λ³€ μƒνƒœκ°€ μ—†μ–΄μ•Ό ν•©λ‹ˆλ‹€.
  3. λͺ¨λ“  κ²½λ‘œκ°€ constexpr 쑰건을 μΆ©μ‘±ν•΄μ•Ό 함: μ‘°κ±΄λ¬Έμ΄λ‚˜ λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•˜λŠ” 경우, ν•¨μˆ˜μ˜ λͺ¨λ“  κ²½λ‘œκ°€ constexpr 쑰건을 λ§Œμ‘±ν•΄μ•Ό ν•©λ‹ˆλ‹€. 그렇지 μ•ŠμœΌλ©΄ ν•¨μˆ˜κ°€ 컴파일 νƒ€μž„μ— 평가될 수 μ—†μŠ΅λ‹ˆλ‹€.
  4. 컴파일러 지원: λͺ¨λ“  μ»΄νŒŒμΌλŸ¬κ°€ constexpr의 λͺ¨λ“  κΈ°λŠ₯을 μ™„λ²½νžˆ μ§€μ›ν•˜λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€. 특히, 였래된 컴파일러λ₯Ό μ‚¬μš©ν•  경우, 일뢀 constexpr κΈ°λŠ₯이 μ œν•œλ  수 μžˆμŠ΅λ‹ˆλ‹€.
  5. λŸ°νƒ€μž„ μ‚¬μš© κ°€λŠ₯μ„±: constexpr둜 μ •μ˜λœ ν•¨μˆ˜λ‚˜ λ³€μˆ˜λŠ” λ°˜λ“œμ‹œ 컴파일 νƒ€μž„μ— κ³„μ‚°λ˜μ§€ μ•Šμ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 컴파일 νƒ€μž„μ— 인자λ₯Ό μ•Œ 수 μ—†λŠ” 경우 λŸ°νƒ€μž„μ— ν‰κ°€λ©λ‹ˆλ‹€. λ”°λΌμ„œ constexpr이 항상 컴파일 νƒ€μž„μ— ν‰κ°€λœλ‹€κ³  κ°€μ •ν•΄μ„œλŠ” μ•ˆ λ©λ‹ˆλ‹€.

μ˜ˆμ‹œ:

constexpr int foo(int x) {
    if (x > 0) {
        return x * x;
    } else {
        return -x;
    }
}

// 이 ν•¨μˆ˜λŠ” xκ°€ 컴파일 νƒ€μž„μ— 주어진닀면 컴파일 νƒ€μž„μ— ν‰κ°€λ˜μ§€λ§Œ,
// λŸ°νƒ€μž„μ— xκ°€ 주어진닀면 λŸ°νƒ€μž„μ— ν‰κ°€λ©λ‹ˆλ‹€.

이 μ§ˆλ¬Έλ“€μ€ C++μ—μ„œμ˜ constexpr의 κ°•λ ₯ν•œ κΈ°λŠ₯κ³Ό κ·Έ 적용 κ°€λŠ₯성을 더 깊이 μ΄ν•΄ν•˜λŠ” 데 도움이 될 κ²ƒμž…λ‹ˆλ‹€. constexprλŠ” μ„±λŠ₯ μ΅œμ ν™”μ™€ μ½”λ“œ μ•ˆμ •μ„±μ—μ„œ μ€‘μš”ν•œ 역할을 ν•˜λ©°, 이λ₯Ό 적절히 ν™œμš©ν•˜λ©΄ 더 λ‚˜μ€ C++ ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.