В [temp.arg.explicit] / 3 у нас есть это удивительное предложение:
Пакет параметров конечного шаблона, не выведенный иным образом, будет выведен в пустую последовательностьаргументов шаблона.
Что это значит?Что такое пакет параметров конечного шаблона?Что не означает иначе?Это все хорошие вопросы, на которые действительно нет ответов.Но это имеет очень интересные последствия.Подумайте:
template <typename... Ts> void f(std::tuple<Ts...>);
f({}); // ok??
Это ... правильно сформировано.Мы не можем вывести Ts...
, поэтому мы выводим его как пустое.Это оставляет нас с std::tuple<>
, который является совершенно допустимым типом - и совершенно допустимым типом, который может быть создан даже с {}
.Итак, это компилируется!
Так что же происходит, когда то, что мы выводим из пустой пачки параметров, которую мы вызвали , не является допустимым типом?Вот пример :
template <class... Ts>
struct Y
{
static_assert(sizeof...(Ts)>0, "!");
};
template <class... Ts>
std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )
{
return os << std::endl;
}
Потенциальный кандидат operator<<
, но вычет не удался ... или так может показаться.Пока мы не заклинаем Ts...
как пустое.Но Y<>
- недопустимый тип!Мы даже не пытаемся выяснить, что мы не можем построить Y<>
из std::endl
- у нас уже произошел сбой .
Это в принципе та же ситуация, что и сvariant
, поскольку variant<>
не является допустимым типом.
Простое решение - просто изменить шаблон функции с принятия variant<Ts...>
на variant<T, Ts...>
.Это больше не может вывести на variant<>
, что даже невозможно, поэтому у нас нет проблем.