Подтвердить что ты не робот

Являются ли типы замещающих типов несимметричных параметров шаблона взаимозаменяемыми в случае параметра шаблона шаблона

Рассмотрим простой пример:

int x;

template <template <auto> class TT>
struct Foo {
   void foo() {
      TT<(x)> tt;
      static_cast<void>(tt);
   }
};

template <decltype(auto)>
struct Bar { };


int main() {
    Foo<Bar> foobar;
    foobar.foo();
}

[clang], похоже, имеет дело с тем, что decltype(auto) placeholder, несмотря на использование auto в объявлении параметра шаблона шаблона без проблема.

[gcc] с другой стороны - не очень хорошо:

prog.cc:6:13: ошибка: значение 'x' не используется в постоянном выражении


Как обычно - какое поведение ожидается в соответствии со стандартом? Или возможно все возможно, и код плохо сформирован (на этот раз я полагаю, что не могу, но не могу это исключить окончательно)?

PS. Извините за нарушение одного из компиляторов снова;)

4b9b3361

Ответ 1

Исходный ответ здесь имел Foo<Bar> плохо сформированный, я на самом деле сейчас думаю, что он хорошо сформирован. Но, в конечном счете, ошибка clang.


Я действительно думаю, что даже Foo<Bar> плохо сформирован. Новые правила, следующие P0522 что:

Аргумент шаблона соответствует шаблону-шаблону шаблона P, когда P по меньшей мере такой же специализированный, как аргумент template A

где:

Шаблон-параметр шаблона 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) > напрямую, что я не уверен в действительности.

Тем не менее, я не уверен, что этот случай даже был рассмотрен - я не вижу какой-либо формулировки так или иначе, и это стоит поднимать проблему.