Ответ 1
Да, код соответствует стандарту. +
запускает преобразование в простой старый указатель функции для лямбда.
Что происходит:
Компилятор видит первую лямбду ([]{}
) и генерирует объект замыкания согласно п. 5.1.1. Поскольку лямбда является не захватывающей лямбда, применяется следующее:
5.1.2 Лямбда-выражения [expr.prim.lambda]
6 Тип замыкания для лямбда-выражения без лямбда-захвата имеет общедоступную не виртуальную неявную функцию преобразования const для указателя на функцию, имеющую тот же параметр и возвращаемые типы, что и замыкание type вызывает вызов функции. Значение, возвращаемое этой функцией преобразования, должно быть адресом функции, которая при вызове имеет тот же эффект, что и при вызове оператора вызова функции закрытия.
Это важно, так как унарный оператор +
имеет набор встроенных перегрузок, особенно этот:
13.6 Встроенные операторы [over.built]
8 Для каждого типа
T
существуют кандидатные операторные функции вида
T* operator+(T*);
И при этом совершенно ясно, что происходит: Когда оператор +
применяется к объекту замыкания, набор перегруженных встроенных кандидатов содержит указатель преобразования-на-any-pointer, а тип закрытия содержит ровно один кандидат: Преобразование в указатель функции лямбда.
Таким образом, тип test
в auto test = +[]{};
выводится на void(*)()
. Теперь вторая строка проста: для второго объекта лямбда/замыкания назначение указателю функции запускает то же преобразование, что и в первой строке. Несмотря на то, что вторая лямбда имеет другой тип закрытия, результирующий функциональный указатель, конечно, совместим и может быть назначен.