170

我有一种感觉,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

4

7 回答 7

175

未指定 lambda 表达式的类型。

但它们通常只是函子的语法糖。一个 lambda 被直接翻译成一个仿函数。里面的任何东西[]都变成了构造函数参数和仿函数对象的成员,里面的参数()变成了仿函数的参数operator()

可以将不捕获任何变量(在[]'s 内没有任何内容)的 lambda转换为函数指针(如果那是您的编译器,MSVC2010 不支持此功能,但此转换是标准的一部分)。

但是 lambda 的实际类型不是函数指针。这是一些未指定的函子类型。

于 2011-10-31T08:43:34.033 回答
126

它是一个独特的未命名结构,重载了函数调用运算符。lambda 的每个实例都引入了一种新类型。

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

于 2011-10-31T08:44:12.323 回答
29

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

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

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

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

最后一段的结果是,如果您使用转换,您将能够分配LAMBDApFptr.

于 2013-12-29T13:15:10.973 回答
7
#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 引入了新类型(如仿函数)。

于 2011-10-31T08:49:53.713 回答
1

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

于 2017-05-19T19:51:07.823 回答
0

How can I store a boost::bind object as a class member? 中的一个实用解决方案?,尝试boost::function<void(int)>std::function<void(int)>

于 2011-11-08T13:01:09.740 回答
-8

这可能有效:

    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>

于 2020-11-15T00:00:27.447 回答