37

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理由は何ですか?

4

5 に答える 5

21

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

于 2016-03-05T12:59:48.310 に答える
13

重要な更新

以下の分析は、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ます。

于 2011-04-10T15:01:49.857 に答える
1

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

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

于 2016-07-14T08:11:22.067 に答える
-1

minmaxは、定数式を引数として呼び出す場合にのみ定数式になります。それらはそれよりもはるかに一般的に使用できるように意図されているため、宣言を行うことはできません。

これがウィキペディアが言っていることですconstexpr(強調が追加されました)。ウィキペディアが究極のリファレンスではないことは知っていますが、この場合は正しいと思います。

関数での使用はconstexpr、その関数が実行できることに対して非常に厳しい制限を課します。まず、関数は非voidの戻り型を持っている必要があります。次に、関数の内容は次の形式である必要があります:returnexpr。 第三に、exprは引数置換後の定数式でなければなりません。この定数式は、constexprとして定義されている他の関数のみを呼び出すことも、他の定数式データ変数を使用することもできます。

于 2011-04-09T14:33:11.647 に答える
-3

私の推測では、一般的なケースでは、operator <(T、T)もconstexprであることが保証されていません。

于 2011-04-09T13:01:55.423 に答える