20

C++ 標準セクションのドラフトを見ると、5.1.2 ラムダ式の段落2には次のように書かれています (私のものは今後も強調されます)。

ラムダ式の評価は、一時的な prvalue (12.2) になります。この一時的なものはクロージャー オブジェクトと呼ばれます。ラムダ式は、未評価のオペランドに現れてはなりません(第 5 節)。[ 注: クロージャー オブジェクトは関数オブジェクト (20.8) のように動作します。—終了注]

およびセクション5.19 定数式の段落2は次のように述べています。

conditional-expressionは、潜在的に評価される部分式 (3.2) として次のいずれかが含まれていない限り、コア定数式ですが、評価されない論理 AND (5.14)、論理 OR (5.15)、および条件付き (5.16) 演算の部分式は含まれません。考慮されません[...]

次の箇条書きがあります。

— ラムダ式 (5.1.2);

では、評価されていないオペランドではラムダ式が許可されていないのに、定数式の評価されていない部分では許可されているのはなぜでしょうか?

各ラムダには一意の型があるため、評価されていないオペランドの場合、いくつかのケース ( decltypeまたはtypeid ) の型情報があまり役に立たないことがわかります。定数式の未評価のコンテキストでそれらを許可したい理由は明らかではありませんが、おそらくSFINAEを許可するためでしょうか?

4

1 に答える 1

23

評価されていないオペランドを除外する主な理由は、 C++ 標準コア言語の欠陥レポートと承認された問題 #1607 で説明されています。テンプレート パラメーターのラムダは、この制限を明確にすることを目的としており、セクションの制限の意図を次のように述べています5.1.2

[...] 関数テンプレートの署名でそれらを処理する必要性を回避します [...]

問題が文書化しているように、定数式は未評価のコンテキストでそれらを許可するため、現在の文言には実際には穴があります。しかし、この制限の根拠を完全に述べているわけではありません。名前マングリングを回避したいという要望は際立っており、提案された解決策は制限を強化しようとしているため、 SFINAEの拡張を回避することも望まれていたと推測できます5.1.2段落2の修正版は次のとおりです。

ラムダ式は、未評価のオペランド (第 5 節 [expr])、テンプレート引数、エイリアス宣言、typedef 宣言、または関数本体外の関数または関数テンプレートの宣言に現れてはなりません。およびデフォルトの引数 [注: 意図は、ラムダが署名に表示されないようにすることです — 終わりの注] . [注: クロージャー オブジェクトは、関数オブジェクト (20.10 [function.objects]) のように動作します。—終わりのメモ]

この提案は受け入れられ、現在進行中ですN3936(リンクについては、この回答を参照してください) 。

評価されていないオペランドとしてラムダを使用することを避ける根拠のより明確な議論については。comp.lang.cpp.moderatedの評価されていないコンテキストで許可されていないラムダ式の理論的根拠と題されたディスカッションでは、3 つの理由が説明されています。

  1. 可能なSFINAEケースの極端な拡張:

[...]それらが除外された理由は、まさにこの sfinae ケースの極端な拡張によるものでした (コンパイラの Pandora ボックスを開いていました)[...]

  1. 多くの場合、各ラムダには一意の型があるため、それは役に立たないだけです。

    template<typename T, typename U>
    void g(T, U, decltype([](T x, T y) { return x + y; }) func);
    
    g(1, 2, [](int x, int y) { return x + y; });
    

    宣言と呼び出しのラムダの型は(定義により)異なるため、これは機能しません。

  2. 関数シグネチャでラムダを許可すると、ラムダの本体もマングルする必要があるため、名前のマングリングも問題になります。これは、可能なすべてのステートメントをマングルするルールを考え出すことを意味します。これは、少なくとも一部の実装にとっては負担になります。

于 2014-03-06T17:49:39.177 に答える