По мотивам беседы в чате по с++:
Проблема
Следующий код не компилируется по причине того, что тип лямбда выражения является уникальным (
5.1.2.3 The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type — called the closure type — whose properties are described below.):
#include <initializer_list>
int main() {
int s = 0;
for(auto f : {[]{return 1;}, []{return 2;}}) {
s += f();
}
return 0;
}
prog.cpp: In function ‘int main()’: prog.cpp:5:46: error: unable to deduce ‘std::initializer_list<auto>&&’ from ‘{<lambda closure object>main()::<lambda()>{}, <lambda closure object>main()::<lambda()>{}}’ for(auto f : {[]{return 1;}, []{return 2;}}) { ^ prog.cpp:5:46: note: deduced conflicting types for parameter ‘auto’ (‘main()::<lambda()>’ and ‘main()::<lambda()>’)
Решение
Но лямбда выражение без захвата может быть приведено к указателю на функцию (
5.1.2.6 The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual nonexplicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator.), а унарный плюс может быть применен к указателю (
5.3.1.7 The operand of the unary + operator shall have arithmetic, unscoped enumeration, or pointer type and the result is the value of the argument.) Следовательно, применение унарного плюса к лямбда выражению должно привести его к указателю на функцию:
#include <initializer_list>
int main() {
int s = 0;
for(auto f : {+[]{return 1;}, +[]{return 2;}}) {
s += f();
}
return 0;
}
Компилируется gcc, clang, но, к сожалению, не компилируется vs 2015, 2017.
p.s. Все отсылки были к драфту стандарта
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4640.pdf
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Mr.Delphist, Вы писали:
MD>В порядке идеи: а если в std::function эти штуки обернуть, не поможет? Сбацать вектор функций, по нему итерироваться.
MD>Хотя в целом лямбды в плюсах всё ещё оставляют впечатление полуфабриката, это да.
Конечно, можно и std::vector<std::function<int()>>, и даже не прибегая ни к vector, ни к function:
int (*f[])() = {[]{return 1;}, []{return 2;} };
но хотелось заинлайнить через initializer_list.