Ответ 1
Это окончательно похоже на ошибку GCC в реализации нового шаблона шаблона шаблона шаблона С++ частичная поддержка этой функции.
Чтобы определить, является ли частичная специализация более специализированной, чем шаблон класса, частичное упорядочение применяется к 2 соответствующим синтезированным функциям:
//template class:
template<template<class...>class P> void f_foo0(foo<P>);
//Partial specialization
template<template<class P> class P> void f_foo_partial0(foo<P>);
Затем он пытается выполнить вывод аргумента шаблона, вызывая каждую функцию с аргументом, соответствующим другому параметру функции (см. [temp.func.order ])
template<class P> struct Atype{};
template<class ...P> struct ATypePack{};
//Is f_foo_partial at least as specialized as f_foo?
f_foo(foo<AType>{});
//Is f_foo at least as specialized as f_foo_partial?
f_foo_partial(foo<ATypePack>{});
Если аргумент шаблона преуспеть для (1), то f_foo_partial
по меньшей мере такой же специализированный, как f_foo
. Если аргумент шаблона преуспевает для (2), то f_foo
по меньшей мере такой же специализированный, как f_foo_partial
. (См. [temp.deduct.partial]). Тогда, если только один, по крайней мере, такой же специализированный, как другой, то он является более специализированным.
Итак чтобы проверить, вычитается ли аргумент шаблона, затем вывод аргумента шаблона из типа.
Затем для выполнения этого соответствия введенное правило в С++ 17 применяется [temp.arg.template]/3:
Аргумент шаблона соответствует шаблону-шаблону шаблона P, если P по меньшей мере такой же специализированный, как шаблон-аргумент A. [...]
И [temp.arg.template]/4 указывают, что это упорядочение будет выполняться аналогично предыдущему случаю, используя эти изобретенные две функции:
template<class...> struct X{};
//for the argument
template<class...P> void f_targ(X<P...>);
//Partial specialization
template<class P> void f_tparam(X<P>);
struct Atype{};
struct ATypePack{};
//Is template template parameter at least as specialized template template arg?
f_targ(X<AType>{});
//Is template template arg at least as specialized as template template parameter?
f_tparam(X<ATypePack>{});
-
для (1) аргумент шаблона успешно выводит аргумент для
...P`` is
AType`. -
для (2) существует специальное правило, которое применяется только в случае частичного заказа шаблона [temp.deduct.type]/9.2:
[...] При частичном упорядочении, если Ai первоначально было расширением пакета:
если P не содержит аргумент шаблона, соответствующий Ai, тогда Ai игнорируется,
в противном случае, если Pi не является расширением пакета, вывод аргумента шаблона не выполняется.
Здесь Ai ATypePack
, а Pi
- P
в аргументе функции template<class P> void p_foo_partial(foo<P>)
.
Поэтому из-за этого правила, выделенного жирным шрифтом, вывод аргумента шаблона не выполняется для (2), поэтому параметр шаблона шаблона "класс P" более специализирован, чем его аргумент. Таким образом, вызов f_foo_partial(foo<ATypePack>{})
хорошо сформирован.
С другой стороны, те же правила, вызов f_foo(AType{})
хорошо сформирован из-за [temp.arg.temp]/3:
[...] Если P содержит пакет параметров, тогда A также соответствует P, если каждый из параметров шаблона A соответствует соответствующему параметру шаблона в списке параметров шаблона P. [...]
поэтому f_foo_partial
не является более специализированным, чем f_foo
, поэтому template<class<class > class C> struct foo<C>;
не является частичной специализацией шаблона foo
.