これは有効なコードです:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
const int xVal { 0 };
const int yVal { 0 };
};
しかし、ここで私は本当にxVal
とyVal
constexpr
を次のように宣言したいと思います。
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
constexpr int yVal { 0 }; // error!
};
示されているように、コードはコンパイルされません。その理由は(7.1.5/1に従って)、静的データメンバーのみがconstexpr
として宣言される可能性があるためです。しかしなぜ?
constexpr
の意味を考えてください。これは、コンパイル時にこの値を解決できることを意味します。
したがって、クラスのメンバー変数自体をconstexpr
にすることはできません... xVal
が属するインスタンスはインスタンス化時まで存在しません! xVal
を所有するものはconstexp
であり、xVal
はconstexpr
になりますが、xVal
がconstexpr
自体。
これは、これらの値をconst式にできないことを意味するわけではありません...実際、クラスのconstexprインスタンスは変数をconst式として使用できます。
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
int xVal { 0 };
int yVal { 0 };
};
constexpr S s;
template <int f>//requires a constexpr
int foo() {return f;}
int main()
{
cout << "Hello World" << foo<s.xVal>( )<< endl;
return 0;
}
編集:それで、ここに暗黙の質問がいくつかあったことをレビューした以下の議論がたくさんありました。
次の例を見てください。
//a.h
struct S;
struct A {std::unique_ptr<S> x; void Foo(); A();/*assume A() tries to instantiate an x*/}
//main.cpp
int main(int argc, char** argv) {
A a;
a->foo();
}
//S.h
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
constexpr int yVal { 0 };
};
AとSの定義は完全に異なるコンパイル単位である可能性があるため、Sがconstexprである必要があるという事実は、特にAの実装を忘れた場合、リンク時までわからない可能性があります。このようなあいまいなケースは、デバッグや実装が困難です。さらに悪いのは、Sのインターフェイスが共有ライブラリ、COMインターフェイスなどで完全に公開される可能性があることです。これにより、共有ライブラリのすべてのインフラストラクチャが完全に変更される可能性があり、それはおそらく受け入れられません。
別の理由は、それがいかに感染性であるかでしょう。クラスのメンバーのいずれかがconstexprである場合、すべてのメンバー(およびそのすべてのメンバー)とすべてのインスタンスはconstexprである必要があります。次のシナリオを考えてみましょう。
//S.h
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
int yVal { 0 };
};
排他的にconstexpr
constexpr
を保持できるようにするには、Sのインスタンスはxval
である必要があります。 yVal
はconstexpr
であるため、本質的にxVal
になります。あなたがそれを行うことができない(私は考えていません)技術的なコンパイラの理由はありませんが、それは非常にC++のように感じません。
たぶん、標準委員会以外はそれが良い考えだとは思わなかったでしょう。個人的には、実用性がほとんどないことに気づきます...私が実際にクラスを使用する方法を定義するのではなく、クラスを使用するときのクラスの動作を定義するだけです。彼らがそれを使うとき、彼らは(上記のように)constexprとして特定のインスタンスを宣言することができます。 constexprインスタンスを必要とするコードブロックがある場合は、テンプレートを使用して実行します。
template <S s>
function int bar(){return s.xVal;}
int main()
{
cout << "Hello World" << foo<bar<s>()>( )<< endl;
return 0;
}
制限的な方法と非制限的な方法の両方で使用できるconstexpr関数を使用したほうがよいと思いますが?
constexpr int bar(S s) { return s.xVal; }