11

在 C++0x 中,我想知道 lambda 函数的类型是什么。具体来说:

#include<iostream>

type1 foo(int x){
 return [x](int y)->int{return x * y;};
}

int main(){

 std::cout<<foo(3)(4);//would output 12

 type2 bar = foo(5);
 std::cout<<bar(6);//would output 30
 return 0;
}

我需要用什么替换 type1/type2 才能使上述内容正常工作?希望您能看到我要完成的工作,因此即使直接替换 type1 和 type2 无法做到这一点,也许您可​​以引导我朝着正确的方向前进。

换句话说:

  • 如何让函数返回匿名函数?
  • 如何将匿名函数分配给变量?

谢谢!

编辑:我正在使用 Visual Studio 2010 进行编译

4

2 回答 2

16

您永远无法知道 lambda 函数的类型,因为逻辑上发生的是编译器生成一个(本地)类,其中函数调用运算符重载,并且词法闭包由该(本地)类的数据成员表示。这就是 lambda 函数在逻辑上发生的情况,例如:

auto foo = [](int x, int y) { return x + y; };

编译器在逻辑上这样做:

struct CompilerGeneratedName { void operator()(int x, int y) const { return x + y; } };
CompilerGeneratedName foo;

由于编译器生成一个(本地)类,它生成一个名称,因此您永远不能显式编写类型,您只能从模板函数参数的类型推导或使用 auto/decltype 推导出类型。

此外,C++0x 闭包是静态分配的,因此无论如何您都不能安全地返回原始 C++0x 闭包。

仍然有几种方法可以实现这一点,第一种更灵活并且支持捕获词法范围的 lambda 函数。使用 std::function,如果你有一个没有从外部范围捕获任何东西的 lambda 函数,那么你可以使用函数指针,但是这种转换更多地用于处理遗留代码而不是任何东西。

所以基本上你想要的是这样的:

std::function< int (int) > foo(int x)
{
    return [x](int y)->int{return x * y;};
}

The reason why I kept on saying logically, is because this is how boost::lambda kind of works originally (even though C++03 does not allow local classes to used in template function arguments) and where the idea of adding lambda functions originate from but since this is a language feature now compiler vendors could implement it in different and more efficient ways like when capturing all of the environment by reference the compiler can just pass a pointer to the call stack instead of the logical way while still maintaining the logical view.

于 2010-07-01T20:21:42.330 回答
6

来自维基百科

Lambda 函数是依赖于实现类型的函数对象;此类型的名称仅对编译器可用。如果用户希望将 lambda 函数作为参数,则该类型必须是模板类型,或者必须创建一个std::function来捕获 lambda 值。

VC10 编译这个

//Beware, brain-compiled code ahead!
#include<iostream>
#include<functional>

std::function<int(int)> foo(int x)
{
    return [x](int y)->int{return x * y;};
}

int main(){

    std::cout<<foo(3)(4) << '\n';

    auto bar = foo(5);
    std::cout<<bar(6) << '\n';

    return 0;
}

并打印

12
30
于 2010-07-01T20:02:16.263 回答