747

constexprとの違いは何constですか?

  • そのうちの1つだけを使用できるのはいつですか?
  • いつ両方を使用でき、どのように選択すればよいですか?
4

10 に答える 10

719

基本的な意味と構文

両方のキーワードは、オブジェクトと関数の宣言で使用できます。オブジェクトに適用した場合の基本的な違いは次のとおりです。

  • constオブジェクトを定数として宣言します。これは、一度初期化されると、そのオブジェクトの値が変更されないという保証を意味し、コンパイラーはこの事実を最適化に利用できます。また、初期化後に変更することを意図していないオブジェクトを変更するコードをプログラマーが作成するのを防ぐのにも役立ちます。

  • constexpr標準が定数式と呼ぶもので使用するのに適したオブジェクトを宣言します。ただし、constexprこれを行う方法はそれだけではないことに注意してください。

関数に適用した場合の基本的な違いは次のとおりです。

  • const非静的メンバー関数にのみ使用でき、一般的な関数には使用できません。これにより、メンバー関数が非静的データメンバーを変更しないことが保証されます(とにかく変更できる可変データメンバーを除く)。

  • constexprコンストラクターだけでなく、メンバー関数と非メンバー関数の両方で使用できます。定数式で使用するのに適した関数を宣言します。コンパイラーは、関数が特定の基準(7.1.5 / 3,4)、最も重要なこと(†)を満たしている場合にのみそれを受け入れます。

    • 関数本体は非仮想で非常に単純である必要があります。typedefとstaticassertを除いて、単一のreturnステートメントのみが許可されます。コンストラクターの場合、初期化リスト、typedef、および静的アサートのみが許可されます。(ただし= default= delete許可されています。)
    • C ++ 14の時点で、ルールはより緩和されており、それ以降、constexpr関数内で許可されています:asm宣言、ステートメント、 andgoto以外のラベルを持つステートメント、try-block、非リテラルの変数の定義タイプ、静的またはスレッドの保存期間の変数の定義、初期化が実行されない変数の定義。casedefault
    • 引数と戻り型はリテラル型である必要があります(つまり、一般的に言えば、非常に単純な型、通常はスカラーまたは集計)

定数式

上記のようにconstexpr、定数式での使用に適したオブジェクトと関数の両方を宣言します。定数式は単なる定数ではありません。

  • テンプレートパラメータや配列サイズ指定子など、コンパイル時の評価が必要な場所で使用できます。

      template<int N>
      class fixed_size_list
      { /*...*/ };
    
      fixed_size_list<X> mylist;  // X must be an integer constant expression
    
      int numbers[X];  // X must be an integer constant expression
    
  • ただし、注意してください。

  • 何かを宣言してconstexprも、コンパイル時に評価されるとは限りません。そのような場合に使用できますが、実行時に評価される他の場所でも使用できます。

  • オブジェクト、宣言されていなくても定数式での使用に適している場合がありますconstexpr。例:

         int main()
         {
           const int N = 3;
           int numbers[N] = {1, 2, 3};  // N is constant expression
         }
    

    これが可能なのはN、が定数であり、宣言時にリテラルで初期化されるため、宣言されていなくても定数式の基準を満たしているためですconstexpr

では、実際にいつ使用する必要がありますconstexprか?

  • 上記のようなオブジェクト、宣言せずNに定数式として使用できます。これは、次のすべてのオブジェクトに当てはまります。constexpr
  • const
  • 積分型または列挙型
  • 宣言時に、それ自体が定数式である式で初期化されます

[これは§5.19/2によるものです。定数式には、「[…]整数型または列挙型のリテラル[…]でない限り、左辺値から右辺値への変更」を含む部分式を含めることはできません。以前は、これはすべてのリテラル型に当てはまると主張していました。]

  • 関数を定数式での使用に適合させるには、明示的に宣言する必要がありconstexprます。定数式関数の基準を満たすだけでは不十分です。例:

     template<int N>
     class list
     { };
    
     constexpr int sqr1(int arg)
     { return arg * arg; }
    
     int sqr2(int arg)
     { return arg * arg; }
    
     int main()
     {
       const int X = 2;
       list<sqr1(X)> mylist1;  // OK: sqr1 is constexpr
       list<sqr2(X)> mylist2;  // wrong: sqr2 is not constexpr
     }
    

いつ/両方constconstexpr 一緒に使用する必要がありますか?

A.オブジェクト宣言内。両方のキーワードが宣言される同じオブジェクトを参照している場合、これは必要ありません。constexprを意味しconstます。

constexpr const int N = 5;

と同じです

constexpr int N = 5;

ただし、キーワードがそれぞれ宣言の異なる部分を参照している場合があることに注意してください。

static constexpr int N = 3;

int main()
{
  constexpr const int *NP = &N;
}

ここでNPは、アドレス定数式、つまりそれ自体が定数式であるポインタとして宣言されています。(これは、アドレス演算子を静的/グローバル定数式に適用することによってアドレスが生成される場合に可能です。)ここで、constexprconstは必須です。constexpr常に宣言されている式(ここNP)をconst参照し、参照int(ポインターを宣言します-) to-const)。を削除するconstと、式が不正になります((a)非定数オブジェクトへのポインターを定数式にすることはできず、(b)&N実際には定数へのポインターであるため)。

B.メンバー関数の宣言。C ++ 11では、をconstexpr意味constしますが、C++14およびC++17ではそうではありません。C++11で宣言されたメンバー関数

constexpr void f();

として宣言する必要があります

constexpr void f() const;

関数として引き続き使用できるようにするために、C++14の下でconst

于 2013-01-02T05:10:47.840 に答える
146

const変数に適用され、コード内で変数が変更されるのを防ぎます。

constexprこの式コンパイル時定数値になることをコンパイラーに通知するため、配列の長さ、const変数への割り当てなどの場所で使用できます。Oliによって提供されるリンクには、多くの優れた例があります。

基本的に、これらは完全に2つの異なる概念であり、一緒に使用できます(そして一緒に使用する必要があります)。

于 2013-01-02T01:44:42.583 に答える
78

概要

  • constプログラムがオブジェクトの値を変更しないことを保証します。ただし、constオブジェクトがどのタイプの初期化を受けるかを保証するものではありません。

    検討:

    const int mx = numeric_limits<int>::max();  // OK: runtime initialization
    

    この関数max()は、リテラル値を返すだけです。ただし、初期化子は関数呼び出しであるため、mx実行時の初期化が行われます。したがって、定数式として使用することはできません。

    int arr[mx];  // error: “constant expression required”
    
  • constexprは、マクロとハードコードされたリテラルを作成する必要がない新しいC++11キーワードです。また、特定の条件下で、オブジェクトが静的に初期化されることを保証します。式の評価時間を制御します。その式のコンパイル時評価を適用することにより、タイムクリティカルなアプリケーション、システムプログラミング、テンプレート、および一般的に言えば、コンパイル時定数に依存するコードで重要なconstexpr真の定数式を定義できます。

定数式関数

定数式関数は、宣言された関数ですconstexpr。その本体は非仮想である必要があり、typedefとstatic assertを除いて、単一のreturnステートメントのみで構成されている必要があります。その引数と戻り値はリテラル型でなければなりません。非定数式の引数で使用できますが、それが行われると、結果は定数式ではなくなります。

定数式関数は、パフォーマンスや型の安全性を犠牲にすることなく、マクロハードコードされたリテラルを置き換えることを目的としています。

constexpr int max() { return INT_MAX; }           // OK
constexpr long long_max() { return 2147483647; }  // OK
constexpr bool get_val()
{
    bool res = false;
    return res;
}  // error: body is not just a return statement

constexpr int square(int x)
{ return x * x; }  // OK: compile-time evaluation only if x is a constant expression
const int res = square(5);  // OK: compile-time evaluation of square(5)
int y = getval();
int n = square(y);          // OK: runtime evaluation of square(y)

定数式オブジェクト

定数式オブジェクトは、宣言されたオブジェクトですconstexpr。これは、定数式または定数式引数を持つ定数式コンストラクターによって構築された右辺値で初期化する必要があります。

定数式オブジェクトは、const使用前に初期化が必要であり、その初期化子が定数式である必要があることを除いて、宣言されたように動作します。したがって、定数式オブジェクトは、常に別の定数式の一部として使用できます。

struct S
{
    constexpr int two();      // constant-expression function
private:
    static constexpr int sz;  // constant-expression object
};
constexpr int S::sz = 256;
enum DataPacket
{
    Small = S::two(),  // error: S::two() called before it was defined
    Big = 1024
};
constexpr int S::two() { return sz*2; }
constexpr S s;
int arr[s.two()];  // OK: s.two() called after its definition

定数式コンストラクター

定数式コンストラクターは、宣言されたコンストラクターですconstexpr。メンバー初期化リストを持つことができますが、typedefと静的アサートを除いて、本体は空である必要があります。その引数はリテラル型でなければなりません。

コンストラクターの引数がすべて定数式である場合、定数式コンストラクターを使用すると、コンパイラーはコンパイル時にオブジェクトを初期化できます。

struct complex
{
    // constant-expression constructor
    constexpr complex(double r, double i) : re(r), im(i) { }  // OK: empty body
    // constant-expression functions
    constexpr double real() { return re; }
    constexpr double imag() { return im; }
private:
    double re;
    double im;
};
constexpr complex COMP(0.0, 1.0);         // creates a literal complex
double x = 1.0;
constexpr complex cx1(x, 0);              // error: x is not a constant expression
const complex cx2(x, 1);                  // OK: runtime initialization
constexpr double xx = COMP.real();        // OK: compile-time initialization
constexpr double imaglval = COMP.imag();  // OK: compile-time initialization
complex cx3(2, 4.6);                      // OK: runtime initialization

スコット・マイヤーズの著書「 Effective Modern C++」からのヒントconstexpr

  • constexprオブジェクトはconstであり、コンパイル中に既知の値で初期化されます。
  • constexpr関数は、コンパイル中に値がわかっている引数を指定して呼び出されると、コンパイル時の結果を生成します。
  • constexprconstexprオブジェクトと関数は、非オブジェクトと関数よりも幅広いコンテキストで使用できます。
  • constexprオブジェクトまたは関数のインターフェースの一部です。

出典: constexprを使用して、C ++のセキュリティ、パフォーマンス、およびカプセル化を改善します

于 2016-01-01T07:45:24.673 に答える
49

との両方constconstexpr変数と関数に適用できます。それらは互いに類似していますが、実際には非常に異なる概念です。

constとはconstexpr、初期化後に値を変更できないことを意味します。したがって、たとえば:

const int x1=10;
constexpr int x2=10;

x1=20; // ERROR. Variable 'x1' can't be changed.
x2=20; // ERROR. Variable 'x2' can't be changed.

との主な違いはconstconstexprそれらの初期化値がわかっている(評価されている)時間です。const変数の値はコンパイル時と実行時の両方で評価できますconstexprが、常にコンパイル時に評価されます。例えば:

int temp=rand(); // temp is generated by the the random generator at runtime.

const int x1=10; // OK - known at compile time.
const int x2=temp; // OK - known only at runtime.
constexpr int x3=10; // OK - known at compile time.
constexpr int x4=temp; // ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.

コンパイル時または実行時に値がわかっているかどうかを知る主な利点は、コンパイル時定数が必要なときはいつでもコンパイル時定数を使用できるという事実です。たとえば、C ++では、可変長のC配列を指定することはできません。

int temp=rand(); // temp is generated by the the random generator at runtime.

int array1[10]; // OK.
int array2[temp]; // ERROR.

つまり、次のことを意味します。

const int size1=10; // OK - value known at compile time.
const int size2=temp; // OK - value known only at runtime.
constexpr int size3=10; // OK - value known at compile time.


int array3[size1]; // OK - size is known at compile time.
int array4[size2]; // ERROR - size is known only at runtime time.
int array5[size3]; // OK - size is known at compile time.

したがって、const変数は、配列サイズを指定するために使用できるようなコンパイル時定数と、実行時にのみ認識され、配列サイズを定義するために使用できないような実行時定数の両方を定義できます。一方、配列サイズを指定できるコンパイル時定数は常に定義してください。size1size2constexpr

との両方constconstexpr関数にも適用できます。const関数はメンバー関数(メソッド、演算子)である必要があります。ここで、キーワードを適用するconstと、メソッドはメンバー(非静的)フィールドの値を変更できなくなります。例えば。

class test
{
   int x;

   void function1()
   {
      x=100; // OK.
   }

   void function2() const
   {
      x=100; // ERROR. The const methods can't change the values of object fields.
   }
};

Aconstexprは別の概念です。関数(メンバーまたは非メンバー)を、コンパイル時定数が引数として渡された場合にコンパイル時に評価できる関数としてマークします。たとえば、これを書くことができます。

constexpr int func_constexpr(int X, int Y)
{
    return(X*Y);
}

int func(int X, int Y)
{
    return(X*Y);
}

int array1[func_constexpr(10,20)]; // OK - func_constexpr() can be evaluated at compile time.
int array2[func(10,20)]; // ERROR - func() is not a constexpr function.

int array3[func_constexpr(10,rand())]; // ERROR - even though func_constexpr() is the 'constexpr' function, the expression 'constexpr(10,rand())' can't be evaluated at compile time.

ちなみに、constexpr関数は、定数でない引数が渡された場合でも呼び出すことができる通常のC++関数です。ただし、その場合は、constexpr以外の値を取得しています。

int value1=func_constexpr(10,rand()); // OK. value1 is non-constexpr value that is evaluated in runtime.
constexpr int value2=func_constexpr(10,rand()); // ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.

constexpr、メンバー関数(メソッド)、演算子、さらにはコンストラクターにも適用できます。例えば。

class test2
{
    static constexpr int function(int value)
    {
        return(value+1);
    }

    void f()
    {
        int x[function(10)];


    }
};

より「クレイジー」なサンプル。

class test3
{
    public:

    int value;

    // constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.
    constexpr int getvalue() const
    {
        return(value);
    }

    constexpr test3(int Value)
        : value(Value)
    {
    }
};


constexpr test3 x(100); // OK. Constructor is constexpr.

int array[x.getvalue()]; // OK. x.getvalue() is constexpr and can be evaluated at compile time.
于 2018-08-05T16:43:33.907 に答える
43

BjarneStroustrupによる「C++プログラミング言語第4版」の本によると、
const:大まかに「この値を変更しないことを約束します」(§7.5)を意味します。これは主にインターフェイスを指定するために使用されるため、データが変更されることを恐れずに関数に渡すことができます。
コンパイラーは、constによる約束を実行します。
constexpr:おおよそ「コンパイル時に評価される」(§10.4)を意味します。これは主に定数を指定するために使用され、次のようになります

const int dmv = 17; // dmv is a named constant
int var = 17; // var is not a constant
constexpr double max1 = 1.4*square(dmv); // OK if square(17) is a constant expression
constexpr double max2 = 1.4∗square(var); // error : var is not a constant expression
const double max3 = 1.4∗square(var); //OK, may be evaluated at run time
double sum(const vector<double>&); // sum will not modify its argument (§2.2.5)
vector<double> v {1.2, 3.4, 4.5}; // v is not a constant
const double s1 = sum(v); // OK: evaluated at run time
constexpr double s2 = sum(v); // error : sum(v) not constant expression

関数を定数式、つまりコンパイラーによって評価される式で使用できるようにするには、constexprを定義する必要があります。
例えば:

constexpr double square(double x) { return x∗x; }


constexprであるためには、関数はかなり単純でなければなりません。値を計算する単なるreturnステートメントです。constexpr関数は非定数引数に使用できますが、それが行われると、結果は定数式ではなくなります。定数式を必要としないコンテキストでconstexpr関数を非定数式引数で呼び出すことができるため、本質的に同じ関数を2回定義する必要はありません。1回は定数式用、もう1回は変数用です。
いくつかの場所では、定数式は言語規則(たとえば、配列境界(§2.2.5、§7.3)、ケースラベル(§2.2.4、§9.4.2)、いくつかのテンプレート引数(§25.2)、およびconstexprを使用して宣言された定数)。その他の場合、コンパイル時の評価がパフォーマンスにとって重要です。パフォーマンスの問題とは関係なく、(状態が変更できないオブジェクトの)不変性の概念は重要な設計上の懸念事項です(§10.4)。

于 2013-10-02T12:58:10.287 に答える
15

Aconst int varは実行時に動的に値に設定でき、その値に設定されると、変更できなくなります。

Aは、実行時に動的に設定するconstexpr int varことはできませんが、コンパイル時に動的に設定できます。また、その値に設定すると、変更できなくなります。

これが確かな例です:

int main(int argc, char*argv[]) {
    const int p = argc; 
    // p = 69; // cannot change p because it is a const
    // constexpr int q = argc; // cannot be, bcoz argc cannot be computed at compile time 
    constexpr int r = 2^3; // this works!
    // r = 42; // same as const too, it cannot be changed
}

上記のスニペットは正常にコンパイルされ、エラーの原因となるものをコメントアウトしました。

ここで注意すべき重要な概念は、compile timeとの概念ですrun time** know **実行時のパフォーマンスを向上させるために、コンパイル時に可能な限り特定のことを目的とした新しいイノベーションがC++に導入されました。

上記の2つの重要な概念を含まない説明の試みは、幻覚です。

于 2018-07-06T05:10:11.503 に答える
8

@ 0x499602d2がすでに指摘しているconstように、初期化後に値を変更できないことを保証するだけです。as constexpr(C ++ 11で導入)は、変数がコンパイル時定数であることを保証します。
次の例(LearnCpp.comから)を考えてみましょう。

cout << "Enter your age: ";
int age;
cin >> age;

const int myAge{age};        // works
constexpr int someAge{age};  // error: age can only be resolved at runtime
于 2016-06-05T10:33:51.427 に答える
6

どの答えも、それがどのような副作用を持っているのか、あるいは実際にそれが何であるのかを正確に明らかにしているとは思いません。

constexpr名前空間/ファイルスコープでconstは、リテラルまたは式で初期化した場合は同じです。ただし、関数をconst使用すると、任意の関数で初期化できますがconstexpr、非constexpr(constexprまたは非constexpr式でマークされていない関数)で初期化すると、コンパイラエラーが発生します。constexprとは両方ともconst変数の暗黙の内部リンケージです(実際には、-O1以上をコンパイルすると、リンクステージに到達するために存続staticせず、コンパイラに内部(ローカル)リンカーシンボルを発行するように強制しませんconstconstexpr-O1以上。これを行うのは、変数のアドレスを取得する場合のみです。ieでconst表現さconstexprれていない限り、内部シンボルになります。externextern constexpr/const int i = 3;使用する必要があります)。関数でconstexprは、関数が永続的にリンク段階に到達しないようにします(定義または-O0または-Ofastに関係なく)が、決して到達せず、extern-O1inline以上conststaticのみこinlineの影響を及ぼします。const/constexpr変数が関数によって初期化される場合constexpr、負荷は常に最適化フラグで最適化されますが、関数がstaticまたはのみの場合inline、または変数がconst/でない場合、負荷が最適化されることはありませんconstexpr

標準コンパイル(-O0)

#include<iostream>
constexpr int multiply (int x, int y)
{

  return x * y;
}

extern const int val = multiply(10,10);
int main () {
  std::cout << val;
} 

にコンパイルします

val:
        .long   100  //extra external definition supplied due to extern

main:
        push    rbp
        mov     rbp, rsp
        mov     esi, 100 //substituted in as an immediate
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        pop     rbp
        ret

__static_initialization_and_destruction_0(int, int):
        . 
        . 
        . 

でも

#include<iostream>
const int multiply (int x, int y)
{

  return x * y;
}

const int val = multiply(10,10); //constexpr is an error
int main () {
  std::cout << val;
}

にコンパイルします

multiply(int, int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     DWORD PTR [rbp-8], esi
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, DWORD PTR [rbp-8]
        pop     rbp
        ret

main:
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR val[rip]
        mov     esi, eax
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        pop     rbp
        ret

__static_initialization_and_destruction_0(int, int):
        . 
        . 
        . 
        mov     esi, 10
        mov     edi, 10
        call    multiply(int, int)
        mov     DWORD PTR val[rip], eax

constexprこれは、ファイルスコープ変数の初期化がconst/constexprコンパイル時に発生し、グローバルシンボルを生成しないのに対し、それを使用しないと実行前に初期化が発生することを明確に示していmainます。

-Ofastを使用したコンパイル

-Ofastでさえ、負荷を最適化しません!https://godbolt.org/z/r-mhifなので、必要です constexpr


constexprconstexpr同じ結果を得るために、他の関数の内部から関数を呼び出すこともできます。constexpr関数上では、コンパイル時に関数で実行できないものを使用することもできません。たとえば、の<<演算子の呼び出しstd::cout

constexpratブロックスコープは、非constexpr関数によって初期化された場合にエラーを生成するという点で同じように動作します。値もすぐに置き換えられます。

結局、その主な目的はCのインライン関数のようなものですが、この関数を使用してファイルスコープ変数を初期化する場合にのみ有効です(関数はCでは実行できませんが、ファイルの動的初期化が可能であるため、C++では実行できます-スコープ変数)。ただし、関数は、Cで使用extern/staticできる、を使用しても、グローバル/ローカルシンボルをリンカーにエクスポートすることはできません。inlineブロックスコープの変数割り当て関数はconstexpr、CおよびC ++を使用せずに、-O1最適化を使用するだけでインライン化できます。

于 2020-04-10T00:34:31.340 に答える
2

constおよびconstexprキーワードの概要

C ++では、constオブジェクトが定数式で初期化されている場合、定数式が必要な場所であればどこでもconstオブジェクトを使用できます。

const int x = 10;
int a[x] = {0};

たとえば、switchでcaseステートメントを作成できます。

constexprは配列で使用できます。

constexprはタイプではありません。

constexprキーワードは、autoキーワードと組み合わせて使用​​できます。

constexpr auto x = 10;

struct Data {   // We can make a bit field element of struct.   
    int a:x;
 };

constオブジェクトを定数式で初期化すると、そのconstオブジェクトによって生成される式も定数式になります。

定数式:コンパイル時に値を計算できる式。

x *5-4//これは定数式です。コンパイラーの場合、この式を入力することと46を直接入力することの間に違いはありません。

初期化は必須です。読書目的でのみ使用できます。変更できません。これまで、「const」キーワードと「constexpr」キーワードに違いはありません。

注:同じ宣言でconstexprとconstを使用できます。

constexpr const int* p;

Constexpr関数

通常、関数の戻り値は実行時に取得されます。 ただし、constexpr関数の呼び出しは、特定の条件が満たされた場合にコンパイル時の定数として取得されます。

注:関数呼び出しで関数のパラメーター変数に送信される引数、または複数のパラメーターがある場合はすべてのパラメーター変数に送信される引数。CEの場合、関数の戻り値はコンパイル時に計算されます。!!!

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

constexpr int a = 3;
constexpr int b = 5;

int arr[square(a*b+20)] = {0}; //This expression is equal to int arr[35] = {0};

関数がconstexpr関数であるためには、関数の戻り値の型と関数のパラメーターの型が「リテラル型」と呼ばれる型カテゴリーに含まれている必要があります。

constexpr関数は、暗黙的にインライン関数です。

重要なポイント:

constexpr関数は、定数式で呼び出す必要はありません。必須ではありません。この場合、コンパイル時に計算は行われません。通常の関数呼び出しのように扱われます。したがって、定数式が必要な場合、この式は使用できなくなります。

constexpr関数であるために必要な条件を以下に示します。

1)関数のパラメータで使用される型と関数の戻り値の型は、リテラル型である必要があります。

2)静的な有効期間を持つローカル変数を関数内で使用しないでください。

3)関数が有効な場合、コンパイル時に定数式を使用してこの関数を呼び出すと、コンパイラはコンパイル時に関数の戻り値を計算します。

4)コンパイラは関数のコードを確認する必要があるため、constexpr関数はほとんどの場合ヘッダーファイルに含まれます。

5)作成した関数をconstexpr関数にするには、関数の定義をヘッダーファイルに含める必要があります。したがって、そのヘッダーファイルを含むソースファイルには、関数の定義が表示されます。

ボーナス

通常、デフォルトのメンバー初期化では、定数型と整数型の静的データメンバーをクラス内で初期化できます。ただし、これを行うには、「const」と「integraltypes」の両方が必要です。

static constexprを使用する場合、クラス内で初期化するために整数型である必要はありません。定数式で初期化すれば問題ありません。

class Myclass  {
         const static int sx = 15;         // OK
         constexpr static int sy = 15;     // OK
         const static double sd = 1.5;     // ERROR
         constexpr static double sd = 1.5; // OK
 };
于 2021-02-22T12:00:34.340 に答える
1

まず第一に、両方ともc++の修飾子です。constとして宣言された変数は初期化する必要があり、将来変更することはできません。したがって、通常、constとして宣言された変数は、コンパイル前でも値を持ちます。

ただし、constexprの場合は少し異なります。

constexprの場合、プログラムのコンパイル中に評価できる式を指定できます。

明らかに、constexperとして宣言された変数は、constのように将来変更することはできません。

于 2019-06-13T12:59:59.853 に答える