lambda被编译成什么类型​​?

时间:2014-11-09 23:41:47

标签: c++ c++11 lambda

据我所知,所有数据类型必须在编译时知道,而lambda不是类型。 lambda是否被翻译成anonymous struct with operator()std::function包裹?

例如,

std::for_each(v.begin(), v.end(), [](int n&){n++;});

3 个答案:

答案 0 :(得分:14)

as-if rule的变体,C ++ 11标准说:

  

§5.1.2/ 3 [..] 实现可以定义闭包类型   与下面描述的不同,只要不改变   程序的可观察行为,而不是改变:

     

- 闭包类型的大小和/或对齐方式

     

- 闭包类型是否可以轻易复制(第9条),

     

- 闭包类型是标准布局类(第9条)还是

     

- 闭包类型是否为POD类(第9条)。

我相信这就是人们说unspecified时的意思。但是,其他答案中已经说明的保证如下:

原作者:Lightness Races in Orbit

  
    

[C++11: 5.1.2/3]: lambda-expression 的类型(也是闭包对象的类型)是一个唯一的,未命名的     非联合类类型 - 称为闭包类型 - 其属性     如下所述。此类类型不是聚合(8.5.1)。该     闭包类型在最小的块范围,类范围或     包含相应 lambda-expression 的命名空间范围。      [..]

  
     

该子句继续列出此类型的不同属性。这是   一些亮点:

     
    

[C++11: 5.1.2/5]: lambda-expression 的闭包类型有一个公共inline函数调用运算符(13.5.4),其参数和     返回类型由 lambda-expression 描述     分别是 parameter-declaration-clause trailing-return-type [..]

         

[C++11: 5.1.2/6]:没有 lambda-capture lambda-expression 的闭包类型具有公共非虚拟非显式const     转换函数指向具有相同参数的函数     并返回类型作为闭包类型的函数调用操作符。该     此转换函数返回的值应为a的地址     调用时的函数与调用函数具有相同的效果     闭包类型的函数调用操作符。

  

答案 1 :(得分:12)

从标准§5.1.2.3:

  

lambda-expression 的类型是一个唯一的,未命名的非联合类类型

这是它自己的类型。每次。例如:

auto a = []{ return 1; };
auto b = []{ return 1; };

ab必然会有不同的类型。它们都可以转换为std::function<int()>,但不能转换为彼此:

std::function<int()> c = a; // OK
a = b; // NOPE

添加一些示例以增加一些清晰度:

decltype(a) a2 = a; // OK, explicitly specifying the correct type

template <typename F>
void foo(F f) { ... }

foo(a); // calls foo<decltype(a)>, not foo<std::function<int()>

答案 2 :(得分:6)

lambda表达式构造一个未命名的类型,每个类型具有不同的类型。它们不是std::function实现。更多信息请点击此处: What is a lambda expression in C++11?和此处:How to convert a lambda to an std::function using templates

您可以使用以下技巧在特定编译器上公开类型:

void foo(int);

int main() {
    auto a = []{ return 1; };
    auto b = []{ return 1; };

    foo(a);

    foo(b);

    return 0;
}

在我的mac上使用clang进行编译得出:

/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:11:5: error: no matching function for call to 'foo'
    foo(a);
    ^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:8:14>' to 'int' for 1st argument
void foo(int);
     ^
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:13:5: error: no matching function for call to 'foo'
    foo(b);
    ^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:9:14>' to 'int' for 1st argument
void foo(int);

@Barry指出您可以使用typeid代替。如果我在我的系统上打印出typeid(a).name()typeid(b).name(),我会得到:

Z4mainE3$_0
Z4mainE3$_1

哪个demangle到

main::$_0
main::$_1

只是想把它包括在内以保持完整性。我实际上发现错误消息版本更具信息性。 :)