Что такое "трейлинг-пакет параметров",

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

В случае привязки, если один шаблон функции имеет трейлинг-параметр pack, а другой нет, тот, у которого отсутствует параметр, является считается более специализированным, чем тот, у которого есть пустой пакет параметров.

Теперь интересно, какой именно трейлинг-пакет параметров. Что, если какой-либо из

template<class ...> struct tuple { /* ... */ };

template<class T, class...Ts> void foo(tuple<T,Ts...>);

template<class T, class...Ts> void bar(T, Ts...);

есть, а что нет и почему? Заметим также, что кланг считает

template<class T> void f(tuple<T>);

template<class T, class...Ts> void f(tuple<T,Ts...>);

int main()
{  f(tuple<int>());  }   // ambiguous call?

неоднозначно, подразумевая, что foo не имеет завершающего пакета параметров.

Ответы

Ответ 1

Это CWG1395, для которого дефект разрешение недавно проголосовал за проект стандарта С++ 17. В [temp.deduct.partial] добавлено следующее:

... [if] функциональный шаблон F по меньшей мере такой же специализированный, как шаблон функции G и наоборот, и если G имеет завершающий пакет параметров, для которого F не имеет соответствующего параметр, и если F не имеет завершающего пакета параметров, то F более специализирован, чем G.

В стандарте нет явного определения того, что это означает, "trailing parameter pack", но, судя по существующим контекстам, в которых этот термин используется, он ссылается на пакет параметров шаблона, который отображается как самый правый параметр в параметре шаблона список:

template<class T, class... U> struct X;
//                ^^^^^^^^^^

Или пакет функций, который отображается как самый правый параметр в списке параметров функции:

template<class T, class... U> void y(T, U...);
//                                      ^^^^

В текущем черновике все еще содержится этот устаревший пример в [temp.deduct.type]:

template<class T, class... U> void f(T, U...);
template<class T> void f(T);

f(&i); // error: ambiguous

Этот стандартный отчет о дефектах существует уже несколько лет, и GCC и Clang реализовали его разрешения. Они оба согласны с тем, что приведенный выше пример является действительным вызовом второй перегрузки F.

Если GCC и Clang не согласны в области разрешения дефекта. Это понятно, поскольку он был недавно обновлен, чтобы включить предлагаемую стандартную формулировку. В вашем примере пакет не разложен в список параметров функции, а в список аргументов шаблона типа параметра функции:

template<class T, class... U> void g(tuple<T, U...>);
template<class T> void g(tuple<T>);

g(tuple<int>{});

GCC рассматривает это как действительный вызов второй перегрузки G; Кланг рассматривает это как неоднозначное. Правильность Clang может зависеть от того, подразумевается ли "trailing parameter pack" включать трейлинг-пакеты параметров шаблона или только завершающие пакеты параметров функции.

Обратите внимание, что оба компилятора согласны с тем, что C<int> относится ко второй частичной специализации шаблона класса C в следующем примере:

template<class...> struct C;

template<class T, class... U> struct C<T, U...> {};
template<class T> struct C<T> {};

Это похоже на несогласованность в Clang, поскольку стандартные правила для частичного упорядочения специализированных шаблонов классов определяются в части частичного упорядочения шаблонов функций. См. CWG1432.

Ответ 2

Trailing означает "в конце".

Парольный пакет параметров - это пакет параметров, найденный в конце списка параметров шаблона:

template <typename T1, typename... Ts>
void foo();

// ^ Ts... is trailing here

Это не вопрос С++, а английский вопрос.