重要な更新
以下の分析は、1つの重要なことを混乱させるため、間違っています。私が行った次のステートメントは、まったく異なる答えを必要とする1つの重要な詳細を見逃していました。
名前のない参照max
リターンは、そのオペランドを参照します。
ここでの問題は、関数呼び出しの置換がその時点で行われることです。呼び出しの置換に、生成されるそのglvalueの左辺値から右辺値への変換が含まれる場合、定数式の計算中max
に静的ストレージ期間ではなく一時的なものを参照するglvalueからの読み取りは問題ないため、すべてが問題ありません。ただし、読み取りは関数呼び出し置換の外部で行われるため、関数呼び出し置換の結果は左辺値になります。仕様のそれぞれのテキストは言う
参照定数式は、静的ストレージ期間または関数を持つオブジェクトを指定する左辺値コア定数式です。
ただし、max
返される参照は、指定されていない保存期間のオブジェクトを指定する左辺値を生成します。関数呼び出しの置換は、単なるコア定数式ではなく、定数式を生成するために必要です。したがって、動作が保証されていません。max(sizeof(A), sizeof(B))
以下の(古い)テキストは、上記を考慮して読む必要があります。
あなたがそこに固執したくない理由は今のところわかりませんconstexpr
。とにかく、次のコードは間違いなく便利です
template<typename T> constexpr
T const& max(T const& a, T const& b) {
return a > b ? a : b;
}
他の答えが書いていることに反して、これは合法だと思います。のすべてのインスタンス化max
がconstexpr関数である必要はありません。現在のn3242は言う
constexpr関数テンプレートまたはクラステンプレートのメンバー関数のインスタンス化されたテンプレートの特殊化がconstexpr関数またはconstexprコンストラクターの要件を満たさない場合、その特殊化はconstexpr関数またはconstexprコンストラクターではありません。
テンプレートを呼び出すと、引数の演繹によって関数テンプレートの特殊化が生成されます。これを呼び出すと、関数呼び出しの置換がトリガーされます。次の呼び出しを検討してください
int a[max(sizeof(A), sizeof(B))];
size_t
最初に、2つのprvalueを2つの参照パラメーターに暗黙的に変換し、両方の参照をそれらの値を格納する一時オブジェクトにバインドします。この変換の結果は、一時オブジェクトを参照する各ケースのglvalueです(4p3を参照)。これで、関数呼び出し置換は、これら2つのglvalueを取得し、関数本体内で発生するすべてのglvaluea
をそれらのglvalueで置換します。b
return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);
この条件では、5.19p2で許可されている、これらのglvalueの左辺値から右辺値への変換が必要になります。
- 定数式で初期化された不揮発性一時オブジェクトを参照するリテラル型のglvalue
条件式は、第1オペランドまたは第2オペランドのいずれかにglvalueを生成します。名前のない参照max
リターンは、そのオペランドを参照します。また、配列の次元サイズの指定で行われる最終的な左辺値から右辺値への変換は、上記で引用したのと同じルールによって有効になります。
現在、メンバー関数initializer_list
がないことに注意してください。constexpr
これは既知の制限であり、C ++ 0x以降で処理され、おそらくこれらのメンバーになりconstexpr
ます。