当在 C + + 11中用“ auto”推导 lambda 时,lambda 的类型是什么?

我有一种感觉,那种 lambda 是一种函数指针。当我执行下面的测试时,我发现它是错误的(小样)。

#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
long (*pFptr)(int) = LAMBDA;  // ok
auto pAuto = LAMBDA;  // ok
assert(typeid(pFptr) == typeid(pAuto));  // assertion fails !
}

以上代码是否缺少任何一点?如果没有那么,什么是 typeof一个 lambda 表达式时,推导与 auto关键字?

61785 次浏览

Lambda 表达式的类型未指定。

但它们通常只是函数的语法糖。一个 lambda 被直接转换成一个函数。[]中的任何内容都被转换为构造函数参数和函数对象的成员,而 ()中的参数被转换为函数的 operator()的参数。

一个 lambda,它不捕获任何变量(在 []的内部没有) 可以被转换到一个函数指针(MSvc2010不支持这个,如果这是你的编译器,但这个转换是标准的一部分)。

但是 lambda 的实际类型不是函数指针,而是某种未指定的函数类型。

它是重载函数调用运算符的唯一未命名结构。Lambda 的每个实例都引入一个新类型。

在非捕获 lambda 的特殊情况下,这个结构还有一个隐式的转换函数指针。

#include <iostream>
#include <typeinfo>


#define LAMBDA [] (int i)->long { return 0l; }
int main ()
{
long (*pFptr)(int) = LAMBDA;  // ok
auto pAuto = LAMBDA;  // ok


std::cout<<typeid( *pAuto ).name() << std::endl;
std::cout<<typeid( *pFptr ).name() << std::endl;


std::cout<<typeid( pAuto ).name() << std::endl;
std::cout<<typeid( pFptr ).name() << std::endl;
}

函数类型确实是相同的,但是 lambda 引入了新的类型(像一个函数)。

一个实际的解决方案从 我如何存储一个升级: : bind 对象作为类成员?,尝试 boost::function<void(int)>std::function<void(int)>

[C++11: 5.1.2/3]: Lambda 表达式 的类型(也是闭包对象的类型) 是唯一的、未命名的非联合类类型ーー称为 闭合类型ーー其属性如下所述。此类类型不是聚合(8.5.1)。闭包类型在包含相应 Lambda 表情的最小块作用域、类作用域或命名空间作用域中声明。[..]

子句继续列出此类型的各种属性:

[C++11: 5.1.2/5]: Lambda 表情的闭包类型具有公共 inline函数调用操作符(13.5.4) ,其参数和返回类型分别由 Lambda 表情参数-声明-子句拖尾-回程类型描述。[..]

[C++11: 5.1.2/6]:没有 Lambda 捕获Lambda 表情的闭包类型有一个公共的非虚非显式常量转换函数,该函数指向与闭包类型的函数调用操作符具有相同参数和返回类型的函数。这个转换函数返回的值应该是一个函数的地址,当调用该函数时,其效果与调用闭包类型的函数调用运算符相同。

最后一段的结果是,如果使用转换,就可以将 LAMBDA分配给 pFptr

它还应该注意到,lambda 可以转换为函数指针。然而 typeid < > 返回一个不同于 lambda 和通用函数指针的非平凡对象。因此 typeid < > 的测试不是一个有效的假设。一般来说,C + + 11不希望我们担心类型规范,如果给定的类型可以转换为目标类型,那么所有这些都很重要。

这可能会奏效:

    h1 {
font-size:20px;
}
h2{
font-size:18px;
}
p {
font-size: 16px;
}
exmp{
font-size:16px;
color:#000077;
/*font-style: oblique;*/
font-family: Lucida Console;
}
<h1>If you truly insist in defining a datatype other then auto for your lambda variable then I would recommend the following</h1>


<h2>Step 1: </h2>
<p>Typedef a function pointer</p>
<exmp> typedef void(*FuncPointerType)();</exmp>
<p>Note the empty parentheses, this will need to be the same as the arguments later of your lambda <br> Now create a function pointer as you would normaly do.</p>
<exmp>/void (**MyFunction)() = new FuncPointerType([](){});</exmp>
<p>Note that the you will have to go and manually delete the pointer as it is created on the heap<br>Finally call the function pointer, it can be called one of 2 ways:</p>
<exmp>(*(*MyFunction))();</exmp>
<p>OR</p>
<exmp>(*MyFunction)();</exmp>
<p>Note the importance that it should be returnd for a function pointer pointer to just a function pointer.</p>

进一步改进 Jalf的答案

一个不捕获任何变量的 lambda (在[]中没有任何变量)可以转换成一个函数指针

例如:

  typedef int (*Foo)(int a);


auto bar = [](int a){
return a;
};


int tmp = 1;


auto bar2 = [tmp](int a){
return a+tmp;
};


Foo foo = bar; // this is ok
Foo foo2 = bar2; // this gives C/C++(413)