Как пакет параметров шаблона может иметь другие конечные аргументы?

В проекте стандарта C++14 [temp.param]/11 гласит:

Если параметр шаблона основного класса или псевдонима шаблона является пакетом параметров шаблона, он должен быть последним параметром шаблона.

Если вы попытаетесь скомпилировать следующий шаблон, то компилятор будет жаловаться.

template< typename ...Args, void(*f)(Args...) > // ERROR
struct Bar
{};

Но как это работает в этом случае?

template< typename F, F >
struct Bar;

template< typename ...Args, void(*f)(Args...) > // OK ???
struct Bar< void(*)(Args...), f >
{};

Я вижу, что это как-то связано с тем, что он является частью шаблона класса специализации, но почему?

Правило четко гласит, что оно применяется к шаблону первичного класса. Значит ли это, что правила меняются для специализаций?

Я пытался найти это в стандарте, но ничего не смог найти. Можете ли вы пролить свет на это.

1 ответ

Решение

Правило четко гласит, что оно применяется к шаблону первичного класса. Значит ли это, что правила меняются для специализаций?

Да. Все просто потому, что специализация не является шаблоном первичного класса. Так что, если формулировка предназначена для применения ко всем объявлениям шаблонов, это будет так сказать. Вместо этого правило предназначено только для применения к основному шаблону класса (... и шаблонам псевдонимов, которые не могут быть специализированными). Для специализаций такого ограничения нет.

Это принципиально, потому что невозможно предоставить какие-либо аргументы шаблона после пакета параметров шаблона в первичном шаблоне, но это определенно возможно сделать в специализациях. Например, вот один из способов объединения двух 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...>;
};

Это хорошо, это работает, это полезно. Но нет никакой выгоды от возможности писать такие вещи в первичном шаблоне класса / переменной / псевдонима - поэтому это запрещено для простоты.


Как и во всем, что касается C++, здесь, конечно, есть сноска. Вы могли бы предоставить заданный по умолчанию параметр шаблона, который используется для запуска ошибки замещения. Но есть и другие способы решения этой проблемы, и тогда у нас скоро будут Концепции.

Другие вопросы по тегам