Лямбда в параметре шаблона по умолчанию считается частью непосредственного контекста?

Является ли следующий код правильно сформированным С++ 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.