将lambda表达式传递给lambda参数c ++ 11

Cou*_*311 19 c++ lambda icc c++11

我想做这样的事情:

int main()
{
    auto f = [/*some variables*/](/*take lambda function*/)
    {/*something with lambda function*/};

    f([/*other variables*/](/*variables to be decided by f()*/)
    {/*something with variables*/});
}
Run Code Online (Sandbox Code Playgroud)

我知道可以将lambda传递给函数,也可以传递给lambda.以下作品:

int main()
{
    int x=0;
    int y=0;
    auto f = [x,y](double (func)(int)) -> double
    {func(0); return 0.0;};

    f([](int i) -> double
    {return 0.0;});
}
Run Code Online (Sandbox Code Playgroud)

但以下不起作用(只要我将范围变量更改为添加[x])

int main()
{
    int x=0;
    int y=0;
    auto f = [x,y](double (func)(int)) -> double
    {func(0); return 0.0;}

    f([x](int i) -> double    //[x] does not work
    {return 0.0;});
}
Run Code Online (Sandbox Code Playgroud)

这给出了错误:

error: function "lambda [](double (*)(int))->double::operator()" cannot be called with the given argument list
        argument types are: (lambda [](int)->double)
        object type is: lambda [](double (*)(int))->double
Run Code Online (Sandbox Code Playgroud)

谁会想到如何解决这个问题,或者解决这个问题?我正在使用带有std = c ++ 11的intel编译器icpc(ICC)13.1.2

谢谢

Dav*_*eas 31

关于你的问题,有几点需要澄清.第一个是什么是lambda?

lambda表达式是一个简单的表达式,编译器将从中生成一个无法命名的唯一类型,同时它将生成该类型的实例.当你写:[](int i) { std::cout << i; }编译器将为你生成一个大致类型:

struct __lambda_unique_name {
   void operator()(int i) const { std::cout << i; }
};
Run Code Online (Sandbox Code Playgroud)

如您所见,它不是一个函数,而是一个实现operator()const成员函数的类型.如果lambda进行了任何捕获,编译器将生成捕获值/引用的代码.

为角情况下,像上述情况,在没有被捕获的状态的lambda,该语言允许从λ型的指针转换与所述的签名起作用operator()(减去this部分),所以上述的λ可以被隐式转换为函数获取int和返回任何内容的指针:

void (*f)(int) = [](int i) { std::cout << i; }
Run Code Online (Sandbox Code Playgroud)

现在已经说明了基础知识,在你的代码中你有这个lambda:

auto f = [x,y](double (func)(int)) -> double {func(0); return 0.0;};
Run Code Online (Sandbox Code Playgroud)

为函数的参数(即也适用于lambda表达式)的规则确定的参数不能类型的功能,所以参数拉姆达衰减到指针功能(在同样的方式,类型的数组的自变量衰减到指针类型):

auto f = [x,y](double (*func)(int)) -> double {func(0); return 0.0;};
Run Code Online (Sandbox Code Playgroud)

稍后您将尝试传递一个以捕获为参数的lambda.因为存在捕获,所以特殊规则不适用,并且lambda不能转换为指向函数的指针,从而产生您看到的编译器错误.

在当前标准中,您可以采用两种方式之一.您可以使用type-erasure从签名中删除可调用实体的确切类型:

auto f = [x,y](std::function<double(int)> func) -> double {func(0); return 0.0;};
Run Code Online (Sandbox Code Playgroud)

因为a std::function<double(int)>可以使用任何具有适当签名的可调用实体进行初始化,所以这将接受下面代码中的lambdas,代价是通常意味着动态分配和动态分派的类型擦除.

或者,您可以删除语法糖并手动滚动第一个lambda等效项,但将其设为通用.在这种情况下,lambda很简单,这可能是一个有效的选项:

struct mylambda {
   template <typename F>
   double operator()(F fn) const {
      fn(0); return 0.0;
   }
} f;
// then use the non-lambda as you tried:
f([x](int i) -> double {return 0.0;});
Run Code Online (Sandbox Code Playgroud)

最后,如果你足够耐心,你可以等待C++ 14,其中(很可能,它还没有被批准)将支持多态lambda,这简化了上述类的创建:

auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to 'mylambda' above
Run Code Online (Sandbox Code Playgroud)

  • 从我的阅读,以及[本评论](http://stackoverflow.com/questions/7951377/what-is-the-type-of-lambda-when-deduced-with-auto-in-c11 #comment14872356_8050769)`std :: function`是一个比你显示的模板技术更慢的机制,虽然有人说这是由于虚拟调用,而你说这是由于动态分配(虽然你也说动态调度是我假设是"virtual"的同义词.一般来说,你建议使用模板吗? (2认同)

Dan*_*lKO 5

尝试使用std :: function:

#include <functional>
int main()
{
    int x=0;
    int y=0;
    auto f = [x,y](std::function<double(int)> func) -> double
             {func(0); return 0.0;};

    f([x](int i) -> double {return 0.0;});
}
Run Code Online (Sandbox Code Playgroud)