На интуитивном уровне имеет смысл, что лямбда, которая не должна нести никакого состояния (посредством ссылки или иным образом), должна быть чисто конвертируемой в пустой указатель на функцию.Однако недавно я был удивлен, увидев следующее сбой в GCC, Clang и MSVC:
int main(int, char *[]) {
void (*fp)() = []{}; // OK
//fp = [=]{}; // XXX - no user defined conversion operator available
//fp = [&]{}; // XXX - same ...
}
Спецификация C ++ 17 (или, по крайней мере, видимая публичная версия черновика N4713 ), относится в пункте 7 § 8.4.5.1 [expr.prim.lambda.closure] к лямбдам с захватами и без них:
Тип закрытия для неуниверсальной лямбды-expression без лямбда-захвата , чьи ограничения (если таковые имеются) выполнены, имеет функцию преобразования в указатель на функцию со связью языка C ++ (10.5), имеющую тот же параметр и возвращаемые типы, что и оператор вызова функции типа замыкания,...
Однако, изучая формальную грамматику, вы можете увидеть следующее в § 8.4.5 [expr.prim.lambda] :
- лямбда-выражение :
- лямбда-выражение составное выражение
- ...
- лямбда-интродьюсер :
- ...
и в § 8.4.5.2 [expr.prim.lambda.capture] :
- лямбда-захват :
- захват по умолчанию
- список захвата
- захват по умолчанию, список захвата
- захват по умолчанию :
Таким образом, все компиляторы фактически подчинялись букве йЗакон к моему ужасу ...
Почему язык определяет существование захвата как узкое грамматическое различие в объявлении вместо того, чтобы основывать его на том, содержит ли тело ссылки на любое нестатическое / захваченное состояние