web-dev-qa-db-ja.com

C ++ 14では汎用ラムダはどのように機能しますか?

C++ 14標準では、汎用ラムダはどのように機能しますか(引数タイプとしてのautoキーワード)?

それは、異なる引数型コンパイラごとに同じ本体を持つ新しい関数を生成するが型を置換するC++テンプレートに基づいていますか(コンパイル時ポリモーフィズム)、またはJavaのジェネリックに類似しています(型消去)?

コード例:

auto glambda = [](auto a) { return a; };
107
sasha.sochka

汎用ラムダはC++14で導入されました。

単純に、ラムダ式で定義されたクロージャータイプには、C++11の通常の非テンプレート呼び出し演算子ではなく、templated呼び出し演算子があります。のラムダ(もちろん、autoがパラメーターリストに少なくとも1回現れる場合)。

あなたの例:

auto glambda = [] (auto a) { return a; };

glambdaをこのタイプのインスタンスにします:

class /* unnamed */
{
public:
    template<typename T>
    T operator () (T a) const { return a; }
};

C++ 14標準ドラフトn3690の5.1.2/5項は、特定のラムダ式のクロージャータイプの呼び出し演算子の定義方法を指定します。

非ジェネリックlambda-expressionのクロージャータイプには、パブリックインライン関数呼び出し演算子(13.5.4)があり、そのパラメーターと戻り値の型は、lambda-expressionのparameter-declaration-clauseとtrailing-return-typeによってそれぞれ記述されます。 汎用ラムダの場合、クロージャ型にはパブリックインライン関数呼び出し演算子メンバーテンプレート(14.5.2)があり、そのテンプレートパラメータリストは、ラムダのパラメータでautoが発生するたびに1つの発明された型テンプレートパラメータで構成されます-宣言句、出現順。対応するパラメーター宣言が関数パラメーターパック(8.3.5)を宣言している場合、発明された型テンプレートパラメーターはパラメーターパックです。関数呼び出し演算子テンプレートの戻り値の型と関数のパラメーターは、parameter-declaration-clauseのdecl-specifiersのautoをそれぞれの名前で置き換えることにより、lambda-expressionのtrailing-return-typeおよびparameter-declarationclauseから派生します。対応する発明されたテンプレートパラメータ。

最後に:

それは、異なる引数型のコンパイラがそれぞれ同じ本体を持つが型を変更した関数を生成するテンプレートに似ていますか、それともJavaのジェネリックに似ていますか?

上記の段落で説明したように、ジェネリックラムダは、テンプレート化された呼び出し演算子を持つ一意の名前のないファンクターの単なる構文上の砂糖です。それはあなたの質問に答えるはずです:)

124
Andy Prowl

残念ながら、それらはC++ 11の一部ではありません( http://ideone.com/NsqYuq ):

_auto glambda = [](auto a) { return a; };

int main() {}
_

G ++ 4.7の場合:

_prog.cpp:1:24: error: parameter declared ‘auto’
...
_

ただし、、C++ 14での実装方法は 汎用ラムダのPortland提案

_[](const& x, & y){ return x + y; }
_

これにより、ほとんどの場合、匿名ファンクタークラスの通常の作成が行われますが、型の欠如により、コンパイラはテンプレート化されたメンバーoperator()を出力します。

_struct anonymous
{
    template <typename T, typename U>
    auto operator()(T const& x, U& y) const -> decltype(x+y)
    { return x + y; }
};
_

または、新しい提案 汎用(多態)ラムダ式の提案

_auto L = [](const auto& x, auto& y){ return x + y; };

--->

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;
_

そのため、はい、パラメーターの置換ごとに新しいインスタンス化が発生しますが、そのファンクターのメンバーはまだ共有されます(つまり、キャプチャーされた引数)。

25
Sebastian Mach

これは、テンプレートに似ている(または同等の)C++ 14機能(C++ 11にはない)の提案です。たとえば、 N3559 は次の例を提供します。

たとえば、次のステートメントを含む一般的なラムダ式:

auto L = [](const auto& x, auto& y){ return x + y; };

クロージャタイプが作成され、以下の構造体と同様に動作するオブジェクトが作成される場合があります。

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;
15
Cassio Neri