11

C++0x では、ラムダ関数の型が何なのか疑問に思っています。具体的には:

#include<iostream>

type1 foo(int x){
 return [x](int y)->int{return x * y;};
}

int main(){

 std::cout<<foo(3)(4);//would output 12

 type2 bar = foo(5);
 std::cout<<bar(6);//would output 30
 return 0;
}

上記を機能させるには、type1/type2 を何に置き換える必要がありますか? 私が達成しようとしていることを理解していただければ幸いです。type1 と type2 を直接置き換えることができなくても、おそらく正しい方向に導くことができます。

言い換えると:

  • 匿名関数を返す関数を取得するにはどうすればよいですか?
  • 匿名関数を変数に割り当てるにはどうすればよいですか?

ありがとう!

編集:Visual Studio 2010でコンパイルしています

4

2 に答える 2

16

論理的に発生するのは、コンパイラが関数呼び出し演算子をオーバーロードした (ローカル) クラスを生成し、レキシカル クロージャーがその (ローカル) クラスのデータ メンバーによって表されるため、ラムダ関数の型を知ることはできません。これは、次のようなラムダ関数で論理的に発生することです。

auto foo = [](int x, int y) { return x + y; };

コンパイラは論理的にこれを行います。

struct CompilerGeneratedName { void operator()(int x, int y) const { return x + y; } };
CompilerGeneratedName foo;

コンパイラは (ローカル) クラスを生成するため、名前を生成するため、型を明示的に記述することはできません。型は、テンプレート関数の引数の型推定または auto/decltype を使用して推定することしかできません。

また、C++0x クロージャーは静的に割り当てられるため、生の C++0x クロージャーを安全に返すことはできません。

これを実現する方法はいくつかありますが、最初の方法はより柔軟で、レキシカル スコープをキャプチャするラムダ関数をサポートしています。std::function を使用します。外側のスコープから何もキャプチャしないラムダ関数がある場合は、関数ポインターを使用できますが、この変換は何よりもレガシーコードを操作するためのものです。

したがって、基本的にあなたが望むのはこれです:

std::function< int (int) > foo(int x)
{
    return [x](int y)->int{return x * y;};
}

私が論理的に言い続けた理由は、boost::lambda のようなものはもともと (C++03 ではテンプレート関数の引数でローカル クラスを使用することを許可していませんが) 機能する方法であり、ラムダ関数を追加するというアイデアがどこから生まれたかです。からですが、これは言語機能であるため、コンパイラベンダーは、参照によってすべての環境をキャプチャする場合など、さまざまなより効率的な方法で実装できます。見る。

于 2010-07-01T20:21:42.330 に答える
6

ウィキペディアから:

Lambda 関数は、実装依存型の関数オブジェクトです。この型の名前は、コンパイラでのみ使用できます。ユーザーがパラメーターとしてラムダ関数を使用する場合、その型はテンプレート型であるかstd::function、ラムダ値を取得するために を作成する必要があります。

VC10はこれをコンパイルします

//Beware, brain-compiled code ahead!
#include<iostream>
#include<functional>

std::function<int(int)> foo(int x)
{
    return [x](int y)->int{return x * y;};
}

int main(){

    std::cout<<foo(3)(4) << '\n';

    auto bar = foo(5);
    std::cout<<bar(6) << '\n';

    return 0;
}

とプリント

12
30
于 2010-07-01T20:02:16.263 に答える