Какой тип собирают лямбды?
Как я знаю, все типы данных должны быть известны во время компиляции, а лямбда не является типом. Включена ли лямбда в anonymous struct with operator()
или std::function
?
Например,
std::for_each(v.begin(), v.end(), [](int n&){n++;});
Ответы
Ответ 1
Изменение правила as-if, в стандарте С++ 11 говорится:
§5.1.2/3 [..] Реализация может определять тип замыкания иначе, чем описано ниже, если это не изменит наблюдаемое поведение программы, кроме изменения:
- размер и/или выравнивание типа закрытия,
- разрешен ли тип закрытия тривиально (раздел 9),
- является ли тип закрытия стандартным классом макета (раздел 9) или
- является ли тип замыкания классом POD (раздел 9).
Я считаю, что это то, что люди имеют в виду, когда говорят, что это неуказано. Однако то, что гарантировано, как уже указано в других ответах, следующее:
Оригинальный автор: Легкость гонки на орбите
[C++11: 5.1.2/3]:
Тип лямбда-выражения (который также является типом замыкающего объекта) - это уникальный, неназванный тип неединичного класса - называется типом замыкания - свойства которого описаны ниже. Этот тип класса не является совокупностью (8.5.1). тип закрытия объявляется в наименьшей области блока, классе или область пространства имен, которая содержит соответствующее лямбда-выражение. [..]
В разделе перечислены различные свойства этого типа. Вот некоторые основные моменты:
[C++11: 5.1.2/5]:
Тип замыкания для лямбда-выражения имеет общедоступный оператор вызова функции inline
(13.5.4), параметры которого и тип возврата описываются лямбда-выражениями param-declaration-clause и trailing-return-type соответственно. [..]
[C++11: 5.1.2/6]:
Тип замыкания для лямбда-выражения без лямбда-захвата имеет публичную не виртуальную неявную константу функция преобразования для указателя на функцию с тем же параметром и возвращаемые типы в качестве оператора вызова функции замыкания. значение, возвращаемое этой функцией преобразования, должно быть адресом функция, которая при вызове имеет тот же эффект, что и при вызове оператор замыкания функции вызова вызова.
Ответ 2
Из стандарта §5.1.2.3:
Тип лямбда-выражения... - это уникальный, неназванный тип неединичного класса
Это его собственный тип. Каждый раз. Так, например:
auto a = []{ return 1; };
auto b = []{ return 1; };
a
и b
обязательно будут иметь разные типы. Они оба конвертируются в std::function<int()>
, но не друг к другу:
std::function<int()> c = a; // OK
a = b; // NOPE
Добавьте еще несколько примеров, чтобы добавить некоторую ясность:
decltype(a) a2 = a; // OK, explicitly specifying the correct type
template <typename F>
void foo(F f) { ... }
foo(a); // calls foo<decltype(a)>, not foo<std::function<int()>
Ответ 3
Выражение lambda создает неназванный тип, каждый из которых имеет другой тип. Это не реализация std::function
. Дополнительная информация приведена здесь:
Что такое лямбда-выражение в С++ 11? и здесь: Как преобразовать lambda в std:: function, используя шаблоны
Вы можете раскрыть тип вашего конкретного компилятора с помощью трюка, подобного этому:
void foo(int);
int main() {
auto a = []{ return 1; };
auto b = []{ return 1; };
foo(a);
foo(b);
return 0;
}
Компиляция с clang на моем mac дает:
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:11:5: error: no matching function for call to 'foo'
foo(a);
^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:8:14>' to 'int' for 1st argument
void foo(int);
^
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:13:5: error: no matching function for call to 'foo'
foo(b);
^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:9:14>' to 'int' for 1st argument
void foo(int);
@Barry указывает, что вместо этого вы можете использовать typeid
. Если я распечатаю typeid(a).name()
и typeid(b).name()
в своей системе, я получаю:
Z4mainE3$_0
Z4mainE3$_1
которые соединяются с
main::$_0
main::$_1
Просто хотел включить это для полноты. Я действительно нахожу версию сообщения об ошибке немного более информативной.:)