В правиле четко указано, что оно применяется к шаблону первичного класса. Означает ли это, что правила изменяются для специализаций?
Да. Все просто потому, что специализация не является шаблоном первичного класса. Таким образом, если бы формулировка предназначалась для применения к всем шаблонным объявлениям, она бы сказала так. Вместо этого правило предназначено для применения только к основному шаблону класса (... и шаблонам псевдонимов, которые не могут быть специализированными). Для специализаций такого ограничения нет.
Это принципиально, потому что невозможно предоставить какие-либо аргументы шаблона после пакета параметров шаблона в основном шаблоне, но это определенно возможно сделать в специализациях. Например, вот один из способов объединения двух tuple
специализаций:
template <typename T, typename U>
struct tuple_concat;
template <typename... Ts, typename... Us> // <== parameter pack *after* parameter pack
struct tuple_concat<tuple<Ts...>, tuple<Us...>> {
using type = tuple<Ts..., Us...>;
};
Это хорошо, это работает, это полезно. Но нет никакой выгоды & dagger; от возможности писать такие вещи в первичном шаблоне класса / переменной / псевдонима - поэтому это запрещено для простоты.
<ч />
& dagger; Как и во всем, что касается C ++, здесь, конечно, есть сноска. Вы могли бы предоставить заданный по умолчанию параметр шаблона, который используется для запуска ошибки замещения. Но есть и другие способы решения этой проблемы, и тогда у нас скоро будут Концепции.