Какой тип лямбда выведен с помощью "auto" в С++ 11?

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

#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 лямбда при выводе с ключевым словом auto?

Ответ 1

Тип выражения лямбда не задан.

Но они, как правило, просто синтаксический сахар для функторов. Лямбда переводится непосредственно в функтор. Все, что находится внутри [], превращается в параметры конструктора и члены объекта-функтора, а параметры внутри () превращаются в параметры для функтора operator().

Лямбда, которая не фиксирует никаких переменных (ничего внутри []) не может быть преобразована в указатель на функцию (MSVC2010 не поддерживает это, если это ваш компилятор, но это преобразование является частью стандарта).

Но фактический тип лямбда не является указателем на функцию. Это некоторый неопределенный тип функтора.

Ответ 2

Это уникальная неназванная структура, которая перегружает оператор вызова функции. Каждый экземпляр лямбды вводит новый тип.

В частном случае не захватывающей лямбда структура дополнительно имеет неявное преобразование в указатель функции.

Ответ 3

Тип лямбда-выражения (который также является типом объекта замыкания) - это уникальный, неназванный тип неединичного класса - называемый тип замыкания - свойства которого описаны ниже. Этот тип класса не является совокупностью (8.5.1). Тип закрытия объявляется в наименьшей области блока, области видимости класса или области пространства имен, которая содержит соответствующее лямбда-выражение. [..]

В разделе перечислены различные свойства этого типа. Вот несколько основных моментов:

[C++11: 5.1.2/5]: Тип замыкания для лямбда-выражения имеет общедоступный оператор вызова функции inline (13.5.4), параметры и возвращаемый тип которого описываются параметром-объявления-объявления-лямбда-выражения и возвратом-возвратом- типа соответственно. [..]

[C++11: 5.1.2/6]: Тип замыкания для лямбда-выражения без лямбда-захвата имеет публичную не виртуальную неявную функцию преобразования const для указателя на функцию, имеющую тот же параметр и возвращаемые типы, что и оператор вызова функции замыкания. Значение, возвращаемое этой функцией преобразования, должно быть адресом функции, которая при вызове имеет тот же эффект, что и при вызове оператора вызова функции закрытия.

Следствием этого последнего отрывка является то, что если вы использовали преобразование, вы могли бы назначить LAMBDA pFptr.

Ответ 5

#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;
}

Типы функций действительно одинаковы, но лямбда вводит новый тип (например, функтор).

Ответ 6

Следует также отметить, что лямбда преобразуется в указатель на функцию. Однако typeid < > возвращает объект, не содержащий trvial, который должен отличаться от лямбда к универсальному указателю функции. Таким образом, тест для typeid < > не является допустимым предположением. В общем, С++ 11 не хочет, чтобы мы беспокоились о спецификации типа, все, что имеет значение, если данный тип конвертируется в целевой тип.