Какой тип лямбда-выражения выводится с помощью «auto» в C ++ 11? - PullRequest
120 голосов
/ 31 октября 2011

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

#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?

Ответы [ 6 ]

121 голосов
/ 31 октября 2011

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

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

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

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

97 голосов
/ 31 октября 2011

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

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

22 голосов
/ 29 декабря 2013

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

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

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

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

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

2 голосов
/ 31 октября 2011
#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;
}

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

1 голос
/ 19 мая 2017

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

0 голосов
/ 08 ноября 2011

Практическое решение из Как я могу сохранить объект boost :: bind в качестве члена класса? , попробуйте boost::function<void(int)> или std::function<void(int)>.

...