C++ - constexpr

mohadang·2022년 10월 14일
0

C++

목록 보기
29/48
post-thumbnail
post-custom-banner

템플릿메타프로그래밍

  • 템플릿 굉장히 남용
  • 다소 흥미로운 템플릿 메타 프로그래밍 예제
template<int T>
struct Fibonacci
{
  enum{value = (Fibonacci<T - 1>::value + Fibonacci<T - 2>::value)};
}
  • 템플릿 특수화 처리
template<>
struct Fibonacci<0>
{
  enum{value = 1};
}

template<>
struct Fibonacci<1>
{
  enum{value = 1};
}

template<>
struct Fibonacci<2>
{
  enum{value = 1};
}
  • int x = Fibonacci<45>::value;// 컴파일 시에 계산에서 값 대입
    • !! 몇몇 경우에는 컴파일 계산이 오래 걸리면 컴파일 멈춘다.
    • 왜 위와 같은 프로그래밍을 할 까???
      • 컴파일 도중에 값을 평가하기 위해
      • 최적화
      • 그러나 가독성 심하게 떨어짐
      • 실행중에 값을 구하려면.... Fibonacci 함수를 따로 만들어야 함.
      int num  =0;
      std::cin >> num;
      std::cout << Fibonacci<num>::value << std::endl;// Error 발생

constexpr

  • 컴파일과 런타임에도 모두 사용 할 수 있는 constexpr

    constexpr unsigned int Fibonacci(unsigned int i)
    {
      return (i <= 1u) ? i : (Fibonacci(i - 1) + Fibonacci(i -2));
    }
    • constexpr 키워드를 통해 컴파일러에게 컴파일 타임에 값을 계산할 수 있다면 컴파일 타임에 계산해서 넣는다.
    • 컴파일 타임에 계산 할 수 없다면 런타임에 함수로 호출
    • 템플릿을 안 써서 가독성도 괜찮다
    • 런타임, 컴파일 타임 모두 사용 가능하다
    • 컴파일 시에 값 평가를 강제하기 위해서 템플릿 메타프로그래밍을 남용함
    • 이러지 않아도 컴파일러가 자발적으로 그렇게 해 주는 경우도 있긴 했음
      • 근데 컴파일러 재량이기에 불확실함
      • 원래는 컴파일 최적화 되는 코드인데 다른 프로그래머가 아무것도 모르고 어떤 코드를 추가하게 되면 컴파일러가 최적화를
        못 할 수도 있게 된다, 예를들어 실행시에 콘솔로 값을 얻어 오는 코드라던가...
    • constexpr가 프로그래머의 의도를 보여주는 좀더 나은 방법
      • 컴파일 시에 값을 평가해 달라는 의도, inline과 비슷함.
    • constexpr 변수
      • 컴파일러가 컴파일 도중에 변수들을 반드시 결정 지어줌
      • 결정 못 지으면 에러 발생
    • constexpr 함수
      • 함수는 그럴려고 최대한 노력함
      • 평가할 수 없을 경우 실행시에 그 함수가 호출됨
      • 결정 못 지으면 조용히 넘어감
  • Ex)

constexpr unsigned int Fibonacci(unsigned int i)
{
  return (i <= 1u) ? i : (Fibonacci(i - 1) + Fibonacci(i -2));
}
int main()
{
  int value = 3;
  int result = Fibonacci(value);// OK, 컴파일 중에 결정 못 하니까 함수 호출

  // Error, result2 변수를 반드시 컴파일 시점에 결정해야 하는데 못 하니까 Error
  constexpr int result2 = Fibonacci(value);

  // OK, 컴파일 중에 함수 계산해서 결정할 수 있으니까, 그리고 변수에도 컴파일중게 값 결정 할 수 있으니까.
  constexpr int result3 = Fibonacci(3);
}
  • "컴파일 도중에 반드시 값이 결정되게 하려면 constexpr를 쓰자"
    • 단 컴파일러가 거부할 수 있다
    constexpr int result3 = Fibonacci(30) ;
    //재귀함수 너무 돌리면 컴파일이 뻗을 수 있다.
    //const expression must have a constant Value
    //expression did not evaluate to a constant
  • constexpr 활용
    • 해쉬를 사용할때 키를 문자열로 한다면 문자열 비교가 필요하다
      • 문자열 비교에는 O(N)이 든다
    • 비용을 절감 하려면 문자열을 해쉬로 만듬 : O(N)
    • 그 후에 해쉬값을 비교 : O(1)
    • 허나 여전히 런타임 중에 실행되고 있음
      • 문자열 해쉬를 컴파일 중에 만들 수 있다면??
      • 그럼 문자열 비교에 드는 비용은 언제나 O(1)
      • constexpr를 써서 컴파일 시점에 문자열 해쉬를 만들 수 있게 되었다

const vs constexpr

  • const : 변경을 불허 한다

  • constexpr : 컴파일 시에 계산했으면 좋겠음

  • 서로 같지 않다 !!!

  • 결국 둘다 const 이다

    const int num = 10;
    num = 20;// Error
    
    constexpr int num1 = 20;
    num1 = 30;// Error
    
    int num2 = 30;
    constexpr int num3 = num2;// Error
    
    const int num4 = 40;// OK
    constexpr int num5 = num4;// OK
    
    constexpr int num6 = 60;// OK
    constexpr int num7 = num6;// OK

const vs constexpr 함수

  • const
    • 멤버 함수에만 사용 가능
    • 멤버 변수를 바꿀 수 없음
  • constexpr
    • 멤버와 비멤버 함수에 둘다 사용 가능
    • 멤버변수를 바꿀 수 있음(C++ 14부터)
constexpr int Fibonacci(int num);// OK
int Fibonacci(int num) const;// error, 비멤버함수라서

constexpr int Champion::GetWinCount()// OK
{
  mWinCount = 10;
  return mWinCount;
}

constexpr int Champion::GetWinCount() const// Error, 멤버 변수를 바꾸고 있음.
{
  mWinCount = 10;
  return mWinCount;
}

배열의 길이 정하기

  • enum
class FixedArray
{
public:
private:
  enum { MAX = 10 };
  int mSize;
  int mArray[MAX];
}
  • constexpr
class FixedArray
{
public:
private:
  static constexpr int MAX = 10;
  int mSize;
  int mArray[MAX];
}
  • enum을 선호, 왜냐하면 enum은 그냥 상수인 반면 constexpr(const) 은 여전히 메모리 할당하고 메모리 가지고 있는 변수이다
profile
mohadang
post-custom-banner

0개의 댓글