将指向lambda函数的指针指定给指向另一个lambda函数的指针

syn*_*gma 12 c++ lambda pointers c++11

我试图指定一个指向lambda函数的指针指向另一个lambda函数.代码将说明一切:

#include <iostream>

int main(int argc, char *argv[]) {

    auto l1 = []() { std::cout << "Lambda 1!" << std::endl; };
    auto l2 = [] { std::cout << "Lambda 2!" << std::endl; };

    auto l1p = &l1;
    l1p = &l2; // Why can't I do this assignment?
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

由于两个lambda函数的返回类型和参数是相同的,为什么我不能做这个赋值?

Col*_*mbo 16

[expr.prim.lambda]/2:

的类型的λ-表达(这也是封闭的对象的类型)是一种独特的,无名不愈合类类型-称为闭合类型 -其特性如下所述.

也就是说,两种闭包类型总是完全不同且不相关.但是,在您的示例中,由于两个lambda都没有捕获任何内容,因此可以将它们转换为类型的函数指针void(*)().
所以也许你打算做

void (*l1p)() = l1;
l1p = l2;
Run Code Online (Sandbox Code Playgroud)

  • @SimonKraemer*请*不要.`std :: function`的开销不值得进行轻微的语法改进.只需使用`typedef`. (8认同)
  • @SimonKraemer它是一个类型安全的包装器...用于*any*callable.函数指针,带有operator(),lambda等的手写类.这可能需要堆分配(存储状态)(某些实现具有小的对象优化),但确实涉及vtable或等效的调度.调用开销类似于`()`的虚函数调用,这稍微多于函数指针调用,但更难内联. (2认同)

Que*_*tin 9

作为Columbo答案的补充,您可以使用以下方法同时进行类型推导和lambda-to-function指针衰减operator +:

auto l1p = +l1; // l1p is void (*)()
//         ^
l1p = l2;
Run Code Online (Sandbox Code Playgroud)


Dan*_*our 7

让我们删除lambda函数为我们提供的语法糖:

struct lambda1 {
  void operator () {
    std::cout << "Lambda 1!" << std::endl;
  }
};
struct lambda2 {
  void operator () {
    std::cout << "Lambda 2!" << std::endl;
  }
};
int main(int argc, char *argv[]) {

    auto l1 = Lambda1{};
    auto l2 = Lambda2{};

    auto l1p = &l1; // l1p is a Lambda1 *
    l1p = &l2; // &l2 is a Lambda2 *
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这不是编译器完成的转换,但我认为检查问题就足够了:

这两个lambda都有自己的类型,与它们的参数,捕获的变量或返回类型完全无关.当然,lambda的类型彼此无关,所以你显然不能从另一个的地址指定一个指针.


使用函数指针解决另一个问题的解决方案非常好.如果C++没有"你只用它为它付钱"的学说,我们可以把lambda函数做成像

struct SomeLambda
  : public LambdaBase<
        Capture<int>,
        Arguments<bool>,
        Return<void>> {
  // ...
};
/*
  [integer]
  (bool flag) {
    if (flag) cout << integer;
  }
*/
Run Code Online (Sandbox Code Playgroud)

但是为了理所当然,基础需要是多态的(具有虚拟成员函数),如果你不打算做你想做的事情,这是你不需要的成本.