[Modern C++] 16.2. constexpr

윤정민·2023년 8월 21일
0

C++

목록 보기
42/46

1. constexpr

  • 객체나 함수 앞에 붙일 수 있음
  • 해당 객체나 함수의 리턴값을 컴파일 타임에 알 수 있다는 의미

  • 상수식: 컴파일러가 컴파일 타임에 어떠한 식의 값을 결정할 수 있는 것

  • 예시 코드
#include <iostream>

template <int N>
struct A {
  int operator()() { return N; }
};

int main() {
  constexpr int size = 3;
  int arr[size];  // Good!

  constexpr int N = 10;
  A<N> a;  // Good!
  std::cout << a() << std::endl;

  constexpr int number = 3;
  enum B { x = number, y, z };  // Good!
  std::cout << B::x << std::endl;
}

2. const와의 차이점

  • const로 정의된 상수들을 굳이 컴파일 타임에 그 값을 알 필요가 없음
  • constexpr은 오른쪽에 상수식이 와야함
    • 컴파일 타임에 상수를 확실히 사용하고 싶다면 constexpr 키워드 사용을 지향

3. constexpr함수

  • constexpr을 사용하지 않는다면 메타프로그래밍을 사용해야 함
  • 제약조건
    • goto 문 사용
    • 예외 처리
    • 리터럴 타입이 아닌 변수의 정의
    • 초기화 되지 않는 변수의 정의
    • 실행 중간에 constexpr이 아닌 함수 호출

  • constexpr함수 예시 코드
#include <iostream>

constexpr int Factorial(int n) {
  int total = 1;
  for (int i = 1; i <= n; i++) {
    total *= i;
  }
  return total;
}

int main() {
  int num;
  std::cin >> num;
  std::cout << Factorial(num) << std::endl;
}

4. constexpr 생성자

  • 일반적인 constexpr 함수에서 적용되는 제약조건들 모두 적용
  • 인자들이 반드시 리터럴 타입
  • 해당 클래스는 다른 클래스를 가상 상속 받을 수 없음

  • 예시 코드
#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;
}

5. if constexpr

  • 타입에 따라 형태가 달라지는 함수의 경우 사용 가능
  • 제약 조건
    • bool로 타입 변환될 수 있어야 하는 컴파일 타임 상수식이어야 함
  • 예시 코드
#include <iostream>
#include <type_traits>

template <typename T>
void show_value(T t) {
  if constexpr (std::is_pointer<T>::value) {
    std::cout << "포인터 이다 : " << *t << std::endl;
  } else {
    std::cout << "포인터가 아니다 : " << t << std::endl;
  }
}

int main() {
  int x = 3;
  show_value(x);

  int* p = &x;
  show_value(p);
}
profile
그냥 하자

0개의 댓글