c ++ 0x:通过引用接收lambda作为参数的正确方法


82

定义int->int通过引用接收lambda参数的函数的正确方法是什么?

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

要么

void f(auto& lambda);

我不确定最后一种形式是否为合法语法。

还有其他方法可以定义lambda参数吗?


10
为什么您需要引用lambda?你的意思是const&
deft_code 2011年

Answers:


82

您不能有auto参数。您基本上有两个选择:

选项1:std::function按照您的显示使用。

选项#2:使用模板参数:

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

在某些情况下,选项#2可能更有效,因为它可以避免为嵌入式lambda函数对象分配潜在的堆,但是只有当f可以将其作为模板函数放在标头中时才有可能。与任何模板一样,它也可能增加编译时间和I-cache占用空间。请注意,它可能也没有效果,因为lambda函数对象足够小,可以在std::function对象中内联表示。


1
模板还可以避免跳转到通用非本地代码(在这种情况下,直接执行您的lambda,而不必先跳过通用std::function包装器),从而提高了I-cache占用空间
jalf

5
这句话“如果lambda函数对象足够小,可以在std::function对象中内联表示” ,这会引起误解。Lambda始终可用于内联(编译器可以选择不这样做)。 std::function实现通常使用小对象优化来避免堆分配。如果lambda的捕获列表足够小,它将被存储在其中std::function而不使用堆。除此之外,lambda的大小没有实际意义。
deft_code 2011年

2
@bdonlan:顺便说一下,为什么会出现&void f(F & lambda)
Nawaz

2
@bdonlan:但是const&假定不能更改lambda的成员(按值捕获)。这可能不是用户想要的。
Nicol Bolas

2
@bdonlan已经有一段时间了,但是作为非常量引用传递时,不允许在函数调用中构造临时lambda。在这里最好使用r值参考。
zennehoy

45

我将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


12

我知道已经有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


10
这仅限于可以衰减为函数指针的lambda(不带捕获的lambda),并且还需要指定精确的签名(与std::function情况相同),而模板化版本则没有此限制。
安德里·泰利科

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);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.