본문 바로가기
C++/C++14

C++14 : 완화된 constexpr 제약 (Relaxed constexpr restrictions)

by 개발자J의일상 2022. 4. 15.
반응형

완화된 constexpr 제약 (Relaxed constexpr restrictions)

먼저 constexprC++11에 추가된 기능이다. 주요 아이디어는 런타임이 아닌 컴파일 시간에 계산을 수행하여 프로그램의 성능을 향상시키는 것이다. 개발자가 프로그램을 컴파일하고 완료하면 사용자가 여러 번 실행한다는 점에 주목하자.

아이디어는 컴파일 시간을 보내고 런타임에 시간을 절약하는 것이다. (템플릿 메타프로그래밍과 유사)

 

constexpr은 객체 또는 함수의 값이 컴파일 타임에 평가될 수 있고 표현식이 다른 상수 표현식에서 사용될 수 있음을 지정한다. 예를 들어 아래 코드에서 product()는 컴파일 시간에 평가된다.

// constexpr function for product of two numbers.
// By specifying constexpr, we suggest compiler to 
// to evaluate value at compile time
constexpr int product(int x, int y)
{
    return (x * y);
}
  
int main()
{
    const int x = product(10, 20);
    cout << x;
    return 0;
}
//Output : 200

constexpr로 선언된 함수

 

1. C++11에서 constexpr 함수는 return 문을 하나만 포함해야 한다. C++14둘 이상의 명령문을 허용한다.

2. constexpr 함수는 상수 전역 변수만 참조해야 한다.

3. constexpr 함수는 단순 함수가 아닌 다른 constexpr 함수만 호출 할 수 있다.

4. 함수는 void 유형이 아니어야 하며 접두사 증가 (++v)와 같은 일부 연산자는 constexpr 함수에서 허용되지 않는다.

 

constexpr vs inline functions:

둘 다 성능 향상을 위한 것이며 인라인 함수는 컴파일러가 컴파일 시간에 확장하도록 요청하고 함수 호출 오버헤드 시간을 절약한다. 인라인 함수에서 표현식은 항상 런타임에 평가된다.

constexpr은 다르다. 여기서 표현식은 컴파일 타임에 평가된다.

 

constexpr에 의한 성능 향상의 예:

// A C++ program to demonstrate the use of constexpr
#include<iostream>
using namespace std;
  
constexpr long int fib(int n)
{
    return (n <= 1)? n : fib(n-1) + fib(n-2);
}
  
int main ()
{
    // value of res is computed at compile time. 
    const long int res = fib(30);
    cout << res;
    return 0;
}

위의 프로그램을 GCC에서 실행하면 0.003초가 걸린다.

 

아래 줄에서 const를 제거하면 constexprt의 결과가 const 표현식에서 사용되지 않기 때문에 fib(30)의 값은 컴파일 시간에 평가되지 않는다.

Change,
  const long int res = fib(30);  
To,
  long int res = fib(30);

위와 같이 변경하면 프로그램에 걸리는 시간이 0.017초 더 증가한다.

 

constexpr with constructors:

 

constexpr은 생성자와 객체에서도 사용할 수 있다. constexpr을 사용할 수 있는 생성자에 대한 모든 제한 사항은 이 항목을 참조해라.

//  C++ program to demonstrate uses of constexpr in constructor
#include <bits/stdc++.h>
using namespace std;
  
//  A class with constexpr constructor and function
class Rectangle
{
    int _h, _w;
public:
    // A constexpr constructor
    constexpr Rectangle (int h, int w) : _h(h), _w(w) {}
      
    constexpr int getArea ()  {   return _h * _w; }
};
  
//  driver program to test function
int main()
{
    // Below object is initialized at compile time
    constexpr Rectangle obj(10, 20);
    cout << obj.getArea();
    return 0;
}
//Output : 200

 

constexpr vs const

 

두가지 키워드는 다른 목적을 수행한다. 

constexpr은 주로 최적화를 위한 반면 const는 Pi값과 같은 실질적으로 const 객체를 위한 것이다. 

둘다 멤버 메서드에 적용할 수 있다. 멤버 메서드는 메서드에 의해 실수로 변경되지 않도록 const로 만들어진다. 

반면에 constexpr을 사용하는 아이디어는 코드가 실행될 때 시간을 절약할 수 있도록 컴파일 시간에 표현식을 계산하는 것이다.

const는 비정적 멤버 함수에만 사용할 수 있는 반면 constexpr은 생성자와 함께 멤버 및 비멤버 함수와 함께 사용할 수 있지만 인수와 반환 타입이 literal 타입이어야 한다는 조건이 있다.

 

C++14에서 완화된 제한

 

  • 다음을 제외한 모든 선언
    • static or thread_local 변수
    • initalizers가 없는 변수 선언
  • 조건 분기문 if와 switch
  • 범위 기반 for문을 포함한 모든 반복문
  • 해당 객체의 수명이 상수 표현식 함수 내에서 시작된 경우 객체의 값을 변경하는 표현식. 여기에는 const가 아닌 constexpr로 선언된 비정적 멤버 함수에 대한 호출이 포함됨.

goto문은 C++14 완화된 constexpr 선언 함수에서 금지됨.

 

또한 C++11에서는 constexpr로 선언된 모든 비정적 멤버 함수도 "this"와 관련하여 암시적으로 const로 선언되었다고 명시했다. 그 이후로 제거되었다. 비 정적 멤버 함수는 const가 아닐 수 있다. 그러나 위의 제한 사항에 따라 const가 아닌 constexpr 멤버 함수는 해당 객체의 수명이 상수 표현식 평가내에서 시작된 경우에만 클래스 멤버를 수정할 수 있다.

 

https://google.github.io/styleguide/cppguide.html#Goals
https://en.wikipedia.org/wiki/C%2B%2B14#Alternate_type_deduction_on_declaration
https://www.geeksforgeeks.org/return-type-deduction-in-c14-with-examples/
300x250

댓글