Ответ 1
Исходный ответ здесь имел Foo<Bar>
плохо сформированный, я на самом деле сейчас думаю, что он хорошо сформирован. Но, в конечном счете, ошибка clang.
Я действительно думаю, что даже Новые правила, следующие P0522 что:Foo<Bar>
плохо сформирован.
Аргумент шаблона соответствует шаблону-шаблону шаблона
P
, когдаP
по меньшей мере такой же специализированный, как аргумент templateA
где:
Шаблон-параметр шаблона
P
по меньшей мере такой же специализированный, как шаблон-аргумент шаблонаA
, если, учитывая следующую переписывание двух шаблонов функций, шаблон функции, соответствующийP
, по меньшей мере, такой же специализированный, как шаблон функции, соответствующийA
в соответствии с правилами частичного заказа для шаблонов функций ([temp.func.order]). С учетом изобретенного шаблона классаX
с помощью списка параметров шаблонаA
(включая аргументы по умолчанию):
- Каждый из двух шаблонов функций имеет те же параметры шаблона, что и
P
илиA
.- Каждый шаблон функции имеет один параметр функции, тип которого является специализацией
X
с аргументами шаблона, соответствующими параметрам шаблона из соответствующего шаблона функции, где для каждого параметра шаблонаPP
в списке параметров шаблона функции шаблон, формируется соответствующий шаблонный аргументAA
. ЕслиPP
объявляет пакет параметров, тоAA
является расширением пакетаPP...
([temp.variadic]); в противном случаеAA
является id-выражениемPP
.Если rewrite выдает недопустимый тип, то
P
не является, по меньшей мере, таким же специализированным, какA
.
Это означает, что для проверки правильности Foo<Bar>
мы синтезируем:
template <decltype(auto) I> struct X;
template <auto I> void __f(X<I> ); // P
template <decltype(auto) I> void __f(X<I> ); // A
Все типы здесь действительны (поэтому последний оператор не применяется). Теперь, обычно, когда мы делаем частичное упорядочение в контексте разрешения перегрузки или выбора специализации шаблона класса, в этом случае мы будем искать "более специализированный" шаблон, где F
более специализированный, чем G
, если F
по крайней мере как специализированная как G
и G
, по крайней мере, не такая специализированная, как F
.
Но в этом контексте нам все равно, что более специализировано. Нам нужно P
быть не менее специализированным, как A
. Все это означает, что вычет должен преуспеть от A
до P
. Итак, если мы синтезируем какой-то уникальный тип U
с некоторым значением V
, можем ли вывести X<I>
из X<V>
? Да. Следовательно, P
не менее специализирован как A
, поэтому аргумент template Bar
соответствует шаблону-параметру TT
.
Теперь, передавая эту точку, я бы сказал, что это ошибка clang. Шаблон-параметр шаблона template <auto>
, который мы должны использовать для проверки выражения. С параметром шаблона не-типа auto
мы попытаемся использовать X
как значение, но X
не является допустимым константным выражением, поэтому это должно завершиться неудачно. clang, по-видимому, использует template <decltype(auto) >
напрямую, что я не уверен в действительности.
Тем не менее, я не уверен, что этот случай даже был рассмотрен - я не вижу какой-либо формулировки так или иначе, и это стоит поднимать проблему.