Какой тип собирают лямбды?

Как я знаю, все типы данных должны быть известны во время компиляции, а лямбда не является типом. Включена ли лямбда в 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

Просто хотел включить это для полноты. Я действительно нахожу версию сообщения об ошибке немного более информативной.:)