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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17663732/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:20:11  来源:igfitidea点击:

Pass lambda expression to lambda argument c++11

c++c++11lambdaicc

提问by Couchy311

I would like to do something like this:

我想做这样的事情:

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*/});
}

I know that it is possible to pass a lambda to a function, as well as to a lambda. The following works:

我知道可以将 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;});
}

But the following does not work (as soon as i change the scope variables to add [x])

但以下不起作用(只要我更改范围变量以添加 [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;});
}

which gives the error:

这给出了错误:

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

would anyone have an idea as to how to fix this, or a way around it? I am using the intel compiler icpc (ICC) 13.1.2 with std=c++11

有没有人知道如何解决这个问题或解决方法?我正在使用带有 std=c++11 的英特尔编译器 icpc (ICC) 13.1.2

Thanks

谢谢

回答by David Rodríguez - dribeas

There are a couple of things to clarify regarding your question. The first of which is what is a lambda?

关于您的问题,有几件事需要澄清。第一个是什么是 lambda?

A lambda expression is a simple expression from which the compiler will generate a unique type that cannot be named, and at the same time it will generate an instance of the type. When you write: [](int i) { std::cout << i; }the compiler will generate a type for you that is roughly:

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

struct __lambda_unique_name {
   void operator()(int i) const { std::cout << i; }
};

As you can see, it is nota function, but a type that implements operator()as a constmember function. If the lambda did any capture, the compiler would generate code to capture the value/references.

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

As a corner case, for lambdas like the above, where there is no state being captured, the language allows for a conversion from the lambda type to a pointer to function with the signature of the operator()(minus the thispart), so the lambda above can be implicitly converted to a pointer to function taking intand returning nothing:

作为一个极端情况,对于像上面这样没有捕获状态的 lambda,该语言允许从 lambda 类型转换为指向带有签名的函数的指针operator()(减去this部分),因此上面的 lambda 可以被隐式转换为指向函数的指针,该指针不int返回任何内容:

void (*f)(int) = [](int i) { std::cout << i; }

Now that the basics have been stated, in your code you have this lambda:

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

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

The rules for parameters to functions (that also apply to lambdas) determine that an argument cannot be of type function, so the argument to the lambda decays to a pointer to function (in the same way that an argument of type array decays to a pointer type):

函数参数的规则(也适用于 lambdas)确定参数不能是function类型,因此 lambda 的参数衰减为指向函数的指针(与数组类型的参数衰减为指针的方式相同)类型):

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

At a later point you are trying to pass a lambda that has a capture as an argument. Because there is a capture, the special rule does not apply and the lambda is not convertible to a pointer to function yielding the compiler error that you see.

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

In the current standard you can go one of two ways. You can use type-erasure to remove the exact type of the callable entity from the signature:

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

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

Because a std::function<double(int)>can be initialized with any callableentity with the appropriate signature, this will accept the lambdas in the code below, at the cost of type-erasure that usually implies a dynamic allocation and dynamic dispatch.

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

Alternatively, you can drop the syntactic sugar and roll the first lambda equivalent manually, but make it generic. In this case, where the lambda is simple this could be a valid option:

或者,您可以删除语法糖并手动滚动第一个 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;});

Finally, if you are patient enough, you can wait for C++14, where (most probably, it has not yet been ratified) there will be support for polymorphic lambdaswhich simplify the creation of the above class:

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

auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to 'mylambda' above

回答by DanielKO

Try using std::function:

尝试使用 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;});
}

回答by Casey

You may have to simply bite the bullet and implement your own functors like we did in the dark ages:

您可能只需要硬着头皮实现自己的函子,就像我们在黑暗时代所做的那样:

struct F {
    int x;
    int y;

    F(int x_, int y_) : x(x_), y(y_) {}

    template <typename G>
    double operator() (G&& g) const {
        g(0);
        return 0.0;
    }
};

#include <iostream>

int main()
{
    int x = 0;
    int y = 0;
    auto f = F(x, y);

    f([x](int i){return 0.0;});
    f([](int i){std::cout << i << std::endl;});
}

That should keep you going until your compiler supports C++14 generic lambdas.

这应该会让你继续下去,直到你的编译器支持 C++14 泛型 lambdas。

回答by Thomas Russell

You could try something like the following if you know the type of the lambda beforehand, for instance:

例如,如果您事先知道 lambda 的类型,则可以尝试以下操作:

int main()
{
    int x = 0, y = 0;

    auto f = [x]( int i )->double {
        return (double)x;
    };

    auto f2 = [x,y]( decltype(f) func )->double {
        return func( 0 );
    };

    f2( f );

    return 0;
}

Or alternative you could use the <functional>library for a more generic solution, for instance:

或者,您可以将该<functional>库用于更通用的解决方案,例如:

auto f = [x,y]( std::function<double(int)> func ) { /* Do stuff */ };

回答by user1095108

You can cify a capturing lambda, but this solution has its limitations:

您可以 cify 捕获 lambda,但此解决方案有其局限性:

#include <new>

#include <utility>

namespace
{

template <typename F, int I, typename L, typename R, typename ...A>
inline F cify(L&& l, R (*)(A...) noexcept(noexcept(
  std::declval<F>()(std::declval<A>()...))))
{
  static L l_(std::forward<L>(l));
  static bool full;

  if (full)
  {
    l_.~L();

    new (static_cast<void*>(&l_)) L(std::forward<L>(l));
  }
  else
  {
    full = true;
  }

  return [](A... args) noexcept(noexcept(
      std::declval<F>()(std::forward<A>(args)...))) -> R
    {
      return l_(std::forward<A>(args)...);
    };
}

}

template <typename F, int I = 0, typename L>
inline F cify(L&& l)
{
  return cify<F, I>(std::forward<L>(l), F());
}


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

    f(cify<double(*)(int i)>([x](int i) -> double    //works now
    {return 0.0;}));
}

Clickfor a working example.

单击以获取工作示例。