Лямбда в параметре шаблона по умолчанию считается частью непосредственного контекста?
Является ли следующий код правильно сформированным С++ 17?
template <typename T, int = [](auto t) { decltype(t)::invalid; return 0; }(T{})>
constexpr int f(T) { return 0; }
constexpr int f(...) { return 1; }
static_assert(f(0) == 1);
clang и edg принимают его, а msvc и gcc 1 отклоняют его. Я не могу найти ничего, что говорило бы, что это серьезная ошибка, но я также не могу найти ничего, что говорило бы, что это ошибка вывода.
В С++ 20 есть этот параграф ([temp.deduct] p9):
Лямбда-выражение, появляющееся в типе функции или параметре шаблона, не считается частью непосредственного контекста для целей вывода аргумента шаблона.
что дает понять, что лямбда не является частью непосредственного контекста. Но как насчет С++ 17?
1: в этом контексте у gcc есть ошибка с auto
, но перезапись ее с использованием явных параметров шаблона для лямбды приводит к той же ошибке.
Ответы
Ответ 1
Это явно плохо сформировано в С++ 17, если я правильно понял.
[expr.prim.lambda] (акцент мой)
2 Лямбда-выражение не должно появляться в неоцененном операнде, в аргументе шаблона, [...]
[temp.param] (выделение мое)
9 Стандартным аргументом шаблона является аргумент шаблона ([temp.arg]), указанный после = в параметре шаблона.
В обоих случаях "шаблон-аргумент" является одним и тем же нормативным термином. Поэтому я считаю, что Clang и edg err принимают код в OP как действительный С++ 17.