C++2018.2.8 constexprキーワード詳細

10047 ワード

+11は、書き出されたコードが従来の実行効率よりも優れていることを保証する改善がある.この改善の1つは定数式を生成し,プログラムがコンパイル時の計算能力を利用できるようにすることである.テンプレートメタプログラミングに詳しい場合は、constexprがこれらをより簡単にすることがわかります.テンプレートメタプログラミングを知らないなら、何もありません.constexprは、コンパイル時のプログラミングの利点を簡単に利用できます.
定数式は、主にいくつかの計算がコンパイル時に発生することを許可します.すなわち、実行時ではなくコードコンパイル時に発生します.これは大きな最適化です.コンパイル時にできることがあれば、プログラムが実行されるたびにではなく、一度だけします.特定の値のsineやcosineなど、コンパイル時に既知の定数を計算する必要がありますか?ライブラリ関数sinやcosも使用できますが、実行時のコストがかかります.constexprを使用すると、コンパイル時の関数を作成できます.必要な数値を計算します.ユーザーのパソコンはこれらの仕事をする必要はありません.
constexprプローブ
関数をコンパイル時に計算する能力を取得するには、constexprキーワードをこの関数に指定する必要があります.
constexpr int multiply (int x, int y) {  return x * y; }  //         const int val = multiply( 10, 10 ); 

コンパイル時に計算されるパフォーマンスの最適化に加えて、constexprのもう一つの利点は、関数が以前マクロを呼び出したすべての場合に適用されることを可能にすることである.たとえば、配列sizeを計算する関数がほしいです.sizeは10の倍数です.constexprを使用しない場合は、関数の戻り値で配列のサイズを宣言できないため、マクロを作成するか、テンプレートを使用する必要があります.しかしconstexprを使用すると、constexpr関数を呼び出して配列を宣言することができます.
constexpr int getDefaultArraySize (int multiplier) {  return 10 * multiplier; }  int my_array[ getDefaultArraySize( 3 ) ]; 

constexpr関数の制限
1つのconstexprには、いくつかの厳格な要求があります.
  • 関数にはreturn文が1つしかありません(ごくわずかな例外があります)
  • は、他のconstexpr関数
  • のみを呼び出すことができます.
  • グローバルconstexpr変数
  • のみ使用可能
    注意再帰は制限されません.しかし、1つの戻り文しか許可されていません.では、どのようにして再帰を実現しますか?三元演算子(?:)を使用できます.たとえば、nの乗算を計算します.
    constexpr int factorial (int n) {  return n > 0 ? n * factorial( n - 1 ) : 1; } 

    factorial(2)を使用すると、コンパイラはコンパイル時にこの値を計算します.この方法では、インラインとは異なり、より巧みな計算を実行できます.再帰関数をインラインすることはできません.
    constexpr関数にはいくつかの特徴がありますか?
    1つのconstexpr関数で、実行可能なコードを1行だけ含めることができます.ただしtypedefs、using declaration&&directives、静的断言などを含めることができます.
    constexprと実行時
    constexprとして宣言された関数は、実行時に呼び出されます.この関数のパラメータが非常に多い場合、
    int n;
    cin >> n; factorial( n ); 

    これは、実行時とコンパイル時の関数を別々に書く必要がないことを意味します.
    コンパイル時のオブジェクトの使用
    Circleクラスがある場合:
    class Circle
    {  public:  Circle (int x, int y, int radius) : _x( x ), _y( y ), _radius( radius ) {}  double getArea () const  {  return _radius * _radius * 3.1415926;  }  private:  int _x;  int _y;  int _radius; }; 

    コンパイル期間中にCircleを構築し、彼の面積を算出したいと思っています.
    constexpr Circle c( 0, 0, 10 ); constexpr double area = c.getArea(); 

    事実はあなたがCircleクラスにいくつかの小さな修正をしてこのことを完成することができることを証明しています.まず、コンストラクション関数をconstexprとして宣言する必要があります.次に、getarea関数をconstexprとして宣言する必要があります.コンストラクション関数をconstexprと宣言すると、コンストラクション関数はコンパイル中に実行されます.このコンストラクション関数のパラメータが定数であり、コンストラクション関数にはメンバー変数のconstexpr構造のみが含まれます(したがって、デフォルトの構造はconstexprと見なされます.メンバー変数にconstexpr構造がある限り).
    class Circle
    {  public:  constexpr Circle (int x, int y, int radius) : _x( x ), _y( y ), _radius( radius ) {}  constexpr double getArea ()  {  return _radius * _radius * 3.1415926;  }  private:  int _x;  int _y;  int _radius; }; 

    constexpr vs const
    メンバー関数をconstexprとしてマークすると、ついでにconstとしてマークします.変数をconstexprとマークすると、同じconstです.しかし、逆に成立しない.constの変数や関数はconstexprではない.
    constexprと浮動小数点数
    ここで我々が述べたconstexpr機能はいずれもテンプレートメタプログラミングによって実現できる.しかしconstexprがサポートする能力の一つは、浮動小数点型のデータを計算できることです.doubleとfloatは有効なテンプレートパラメータではないため、テンプレートコンパイル期間を通じて浮動小数点数の値を簡単に計算することはできません.一方constexprでは、コンパイル期間に浮動小数点型データを計算できます.
    constexprの比較
    C++開発者は、ヘッダファイルを修正すると再コンパイルが遅くなるという悩みを早くから受けています.constexprはコンパイル時間を増加させるリスクを導入する可能性があるが、このリスクを低減する技術もある.まず、constexpr関数の同じパラメータは同じ結果を出力するので、memoizedによって出力することができ、実際にGCCはmemoizationをサポートしています.
    constexpr関数memoizeに対応できるため、テンプレート関数をconstexpr関数で置き換える場所では、(コンパイル)性能が悪くなることはありませんが、コードが明確になります.実際には、テンプレートインスタンスの一部を置き換えると、コンパイルが大幅に高速になります.
    最後に、標準はコンパイラが再帰関数の級数を制限することを可能にする.これにより、深さ再帰的なコンパイル性能損失を制限することができる.
    コンパイラのサポート
    constexprはコンパイラがコンパイル期間の再帰をサポートする必要があるので、constexprをサポートするコンパイラは多くないのも不思議ではありません.私が知っているのはG++4.7だけがこの特性をサポートしています.注:私が翻訳するまでintelC++13、Clang 3.1もサポートしていましたが、Vs 2013はサポートしていません.