具有转换功能的lambda指向具有c ++链接的函数的指针

时间:2019-03-29 07:52:57

标签: c++ c++11 lambda c++17

C ++标准具有以下声明:

  

非通用lambda表达式的闭包类型,不包含   满足约束(如果有)的lambda捕获具有一个   将函数转换为指向具有C ++语言链接的函数的指针   (10.5)具有与闭包相同的参数和返回类型   类型的函数调用运算符。

为了更好地理解该语句,我使用cppinsights来查看clang编译器对以下函数的说法。

#include <iostream>

using test = void (*)(int);

int main()
{
    test t = [](int arg) { std::cout << arg << std::endl; };
}

cppinsights将该函数转换为:

#include <iostream>

using test = void (*)(int);

int main()
{

  class __lambda_7_11
  {
    public: inline void operator()(int arg) const
    {
      std::cout.operator<<(arg).operator<<(std::endl);
    }

    public: using retType_7_11 = void (*)(int);
    inline operator retType_7_11 () const
    {
      return __invoke;
    }

    private: static inline void __invoke(int arg)
    {
      std::cout.operator<<(arg).operator<<(std::endl);
    }


  } __lambda_7_11{};

  using FuncPtr_7 = test;
  FuncPtr_7 t = static_cast<void (*)(int)>(__lambda_7_11.operator __lambda_7_11::retType_7_11());
}

通常,编译器会生成一个匿名类,该类的重载operator()以及标准指定的“将函数转换为指向函数的指针”。

我不明白的是,为什么会生成一个“静态__invoke”函数,而“转换函数”在内部调用“ __invoke”(直接作为函数指针)却没有“ __invoke”所期望的任何参数?

2 个答案:

答案 0 :(得分:2)

Cppinsights的工作是正确的。它会返回调用函数的函数指针。

如果采用以下方式编写,它将更具可读性:

inline operator retType_7_11 () const
{
  return &__invoke;
}

但是,在这种情况下,不需要&。

答案 1 :(得分:2)

  

我不明白的是,为什么生成static __invoke函数,并且“转换函数”在内部调用__invoke(直接作为函数指针),却没有{期望的任何参数{1}}?

转换函数不会“内部调用” __invoke,它只是返回 __invoke,即指向__invoke成员函数的指针。请记住,static和非static成员函数之间的区别在于,前者未绑定到该类的特定实例,因此可以将其视为普通函数指针,而不是指向成员。看下面的例子:

static

后者是您希望转换的结果,而cppinsights向您显示的只是实现转换的一种技术:由于lambda表达式具有空闭包,因此编译器生成的函数对象没有状态,没有状态的对象的成员函数可以是struct Test { void f(); static void g(); }; void (Test::*f)() = &Test::f; // pointer to instance-specific member fct. void (*g)() = &Test::g; // ordinary function pointer void (*h)() = Test::g; // no ampersand, this is implicitly a function pointer 成员函数,可以绑定到普通函数指针。