【问题标题】:Proper way to receive a lambda as parameter by referencec++0x:通过引用接收 lambda 作为参数的正确方法
【发布时间】:2011-09-21 11:08:49
【问题描述】:

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

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

void f(auto& lambda);

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

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

【问题讨论】:

  • 为什么需要引用 lambda?你的意思是const&amp;

标签: c++ lambda c++11 function-prototypes function-parameter


【解决方案1】:

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

选项#1:如您所见,使用std::function

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

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

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

【讨论】:

  • 模板还可以通过消除对一般非本地代码的跳转来改善 I-cache 占用空间(在这种情况下,直接执行您的 lambda,而不必先跳过通用的 std::function 包装器)
  • 这句话,"如果 lambda 函数对象足够小,它可能会在 std::function 对象中内联表示" 具有误导性。 Lambda 始终可用于内联(编译器当然可以选择不使用)。 std::function 实现通常使用小对象优化来避免堆分配。如果 lambda 有足够小的 捕获列表 ,它将被存储在 std::function 中而不使用堆。除此之外,lambda 的大小没有任何实际意义。
  • @bdonlan:对了,为什么void f(F &amp; lambda)中有&amp;
  • @bdonlan:但是 const& 假定 lambda 的成员(按值捕获)不能更改。这可能不是用户想要的。
  • @bdonlan 已经有一段时间了,但是作为非常量引用传递不允许在函数调用中构造临时 lambda。此处最好使用 r 值参考。
【解决方案2】:

我会使用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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 这仅限于可以衰减为函数指针的 lambdas(没有捕获的 lambdas),并且还需要指定确切的签名(尽管与 std::function 的情况相同),而模板版本没有没有这个限制。
    • 非常感谢!
    【解决方案4】:

    从 C++ 20 开始,

    void f(auto& lambda);
    

    确实有效(abbreviated function template):

    当占位符类型(autoConcept auto)出现在函数声明或函数模板声明的参数列表中时,该声明声明了一个函数模板,并且为每个占位符添加了一个发明的模板参数模板参数列表

    这完全等同于@bdonlan 的答案中的选项 2:

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

    【讨论】:

    • 如前所述,根据f()的需求,用一些概念来约束F可能会更好
    【解决方案5】:

    void f(auto&amp; lambda);

    差不多了。实际编译的是:

    #include <cassert>
    
    /*constexpr optional*/ const auto f = [](auto &&lambda)
    {
      lambda();
      lambda();
    };
    
    int main()
    {
      int counter = 0;
      f([&]{ ++counter; });
      assert(counter == 2);
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-21
      • 1970-01-01
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      相关资源
      最近更新 更多