web-dev-qa-db-ja.com

std :: max()およびstd :: min()はconstexprではありません

新しい標準がmin(a,b)max(a,b)なしconstexprを定義していることに気づきました。

25.4.7、[alg.min.max]の例:

template<class T> const T& min(const T& a, const T& b);
template<class T> T min(initializer_list<T> t);

これは残念ではありませんか?書きたかったのに

char data[ max(sizeof(A),sizeof(B)) ];

の代わりに

char data[ sizeof(A) > sizeof(B) ? sizeof(A) : sizeof(B) ];
char data[ MAX(sizeof(A),sizeof(B)) ]; // using a macro

それらの理由constexprにすることはできません

35
towi

重要な更新

以下の分析は間違っています。1つの重要なことを混乱させるからです。私が行った次のステートメントは、まったく異なる答えを必要とする1つの重要な詳細を見逃していました。

名前のない参照maxが返すのは、そのオペランドを参照します。

ここでの問題は、関数呼び出し置換がその時点で完了であるということです。呼び出しの置換に、maxが生成するそのglvalueの左辺値から右辺値への変換が含まれる場合、静的ストレージ期間ではない一時的なものを参照するglvalueからの読み取りは問題ないため、すべてが問題ありません定数式の計算中。ただし、読み取りは関数呼び出し置換の外部で行われるため、関数呼び出し置換の結果はlvalueになります。仕様のそれぞれのテキストは言う

参照定数式は、静的ストレージ期間または関数を持つオブジェクトを指定する左辺値コア定数式です。

ただし、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))];

最初に、2つのsize_t prvalueを2つの参照パラメーターに暗黙的に変換し、両方の参照をそれらの値を格納する一時オブジェクトにバインドします。この変換の結果は、一時オブジェクトを参照する各ケースのglvalueです(4p3を参照)。これで、関数呼び出し置換は、これら2つのglvalueを受け取り、関数本体で発生するすべてのabをそれらのglvalueで置き換えます。

return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);

この条件では、5.19p2で許可されている、これらのglvalueの左辺値から右辺値への変換が必要になります。

  • 定数式で初期化された非揮発性の一時オブジェクトを参照するリテラル型のglvalue

条件式は、第1オペランドまたは第2オペランドのいずれかにglvalueを生成します。名前のない参照maxが返すのは、そのオペランドを参照します。また、配列の次元サイズの指定で行われる最終的な左辺値から右辺値への変換は、上記で引用したのと同じルールによって有効になります。


initializer_listには現在constexprメンバー関数がないことに注意してください。これは既知の制限であり、C++ 0x以降で処理されるため、これらのメンバーはconstexprになる可能性があります。

std :: minおよびstd :: max constexpr C++ 14では、これは明らかに、それらをconstexprにしない正当な理由(最近)がないことを意味します。問題が解決しました :-)

15
einpoklum

std::min()およびstd::max()constexprバージョンがC++ 14に含まれていることは、これらの関数(のバージョン)をconstexprにすることに根本的な障害がないことを示しています。 constexprがC++ 11に追加されたとき、これは十分に早く考慮されていなかったようです。

明らかに、比較関数が提供されているバージョンの場合、テンプレートの展開を成功させるには、その関数自体がconstexprである必要があります。

1
Toby Speight