c ++ 0x:参照によりパラメーターとしてラムダを受け取る適切な方法


85

int->int参照によってラムダパラメーターを受け取る関数を定義する正しい方法は何ですか?

void f(std::function< int(int) >& lambda);

または

void f(auto& lambda);

最後の形式が正当な構文であるかどうかはわかりません。

ラムダパラメーターを定義する他の方法はありますか?


10
なぜ参照によってラムダが必要なのですか?どういう意味const&ですか?
deft_code 2011年

回答:


84

autoパラメータを持つことはできません。基本的に2つのオプションがあります。

オプション#1:std::function示したとおりに使用します。

オプション#2:テンプレートパラメータを使用します:

template<typename F>
void f(F &lambda) { /* ... */}

オプション#2は、埋め込まれたラムダ関数オブジェクトへの潜在的なヒープ割り当てを回避できるため、場合によってはより効率的ですfが、テンプレート関数としてヘッダーに配置できる場合にのみ可能です。また、他のテンプレートと同様に、コンパイル時間とIキャッシュのフットプリントが増加する可能性があります。ラムダ関数オブジェクトが十分に小さい場合は、std::functionオブジェクト内でインラインで表される可能性があるため、効果がない場合もあることに注意してください。


1
テンプレートは、一般的な非ローカルコードへのジャンプを排除することで、Iキャッシュのフットプリントを改善することもできます(この場合、std::function最初に汎用ラッパーをジャンプすることなく、ラムダを直接実行します)
jalf 2011年

5
「ラムダ関数オブジェクトが十分に小さい場合、std::functionオブジェクト内でインラインで表される可能性がある」というこの引用は誤解を招く恐れがあります。ラムダは常にインラインで利用できます(コンパイラーはもちろんそうしないことを選択できます)。 std::function実装では通常、ヒープの割り当てを回避するために小さなオブジェクトの最適化を使用します。ラムダのキャプチャリストが十分に小さい場合はstd::function、ヒープを使用せずに格納されます。それ以外は、ラムダのサイズには実際の意味はありません。
deft_code 2011年

2
@bdonlan:ところで、なぜそこ&にあるのvoid f(F & lambda)ですか?
ナワズ2011年

2
@bdonlan:しかし、const&は、ラムダのメンバー(値によるキャプチャ)は変更できないと想定しています。これは、ユーザーが望んでいるものではない可能性があります。
ニコルボーラス2011年

2
@bdonlanしばらく経ちましたが、非const参照として渡すと、関数呼び出しで一時的なラムダを作成できません。ここでは、r値の参照が最適です。
zennehoy 2013

46

私は次のように使用templateします:

template<typename Functor>
void f(Functor functor)
{
   cout << functor(10) << endl;
}

int g(int x)
{
    return x * x;
}
int main() 
{
    auto lambda = [] (int x) { cout << x * 50 << endl; return x * 100; };
    f(lambda); //pass lambda
    f(g);      //pass function 
}

出力:

500
1000
100

デモ:http//www.ideone.com/EayVq


13

私はそれが7年になったことを知っています、しかしこれは他の誰も言及しなかった方法です:

void foo(void (*f)(int)){
    std::cout<<"foo"<<std::endl;
    f(1); // calls lambda which takes an int and returns void
}
int main(){
    foo([](int a){std::cout<<"lambda "<<a<<std::endl;});
}

どの出力:

foo
lambda 1

テンプレートやstd :: functionは必要ありません


12
これは、関数ポインターに減衰できるラムダ(キャプチャなしのラムダ)にのみ制限されstd::function、テンプレートバージョンにはこの制限がありませんが、正確な署名を指定する必要があります(ただし、ケースと同じ)。
AndriyTylychko19年

どうもありがとうございました!
マイクリー

1

void f(auto& lambda);

近いです。実際にコンパイルされるのは次のとおりです。

#include <cassert>

/*constexpr optional*/ const auto f = [](auto &&lambda)
{
  lambda();
  lambda();
};

int main()
{
  int counter = 0;
  f([&]{ ++counter; });
  assert(counter == 2);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.