лямбда с функцией преобразования в указатель на функцию со связью c ++ - PullRequest
2 голосов
/ 29 марта 2019

C ++ стандарт имеет следующий оператор:

Тип замыкания для неуниверсального лямбда-выражения без лямбда-захвата, ограничения которого (если таковые имеются) выполнены, имеет функцию преобразования в указатель нафункция с языковой связью 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());
}

Как обычно, компилятор генерирует анонимный классс оператором (), перегруженным вместе с «функцией преобразования в указатель на функцию», как указано в стандарте.

Что я не понимаю, так это то, почему генерируется функция «static __invoke» и «функция преобразования»внутренне вызывает "__invoke" (непосредственно как указатель на функцию) без какого-либо параметра, ожидаемого "__invoke"?

Ответы [ 2 ]

2 голосов
/ 29 марта 2019

Чего я не понимаю, так это того, почему генерируется функция static __invoke, а «функция преобразования» внутренне вызывает __invoke (непосредственно как указатель на функцию) без какого-либо параметра, ожидаемого __invoke?

Функция преобразования не "внутренне вызывает" __invoke, она просто возвращает __invoke, т.е. указатель на static функцию-член. Помните, что разница между static и не static функциями-членами заключается в том, что первая не связана с конкретным экземпляром этого класса и, следовательно, может рассматриваться как обычные указатели на функции, а не как указатели на члены. Посмотрите на следующий пример:

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

Последнее - это то, что вы намереваетесь получить в результате преобразования, и то, что cppinsights показывает вам, является не чем иным, как техникой реализации этого преобразования: поскольку лямбда-выражение имеет пустое замыкание, объект функции, сгенерированный компилятором, не имеет состояние, и функция-член объекта без состояния может быть static функцией-членом, которая может связываться с указателем на обычную функцию.

2 голосов
/ 29 марта 2019

Cppinsights правильно в том, что он делает.Он возвращает указатель на функцию, вызывая функцию.

Это было бы более читабельно, если бы оно было записано следующим образом:

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

Однако в этом & ndash не требуетсяслучай.

...