Ответ 1
... Пакет параметров конечного шаблона ([temp.variadic]) не иначе выводится как пустая последовательность аргументов шаблона....
Может быть достаточно сказать, что не выведенное иное не является пунктом, который должен каким-то образом или автоматически ослаблять некоторые другие правила, или на самом деле это не имеет никакого отношения к тому, почему он искажен (вопреки тому, что, я думаю, вы подразумеваете).
Возможно, это другое правило лучше всего продемонстрировать на другом простом примере:
template<class T>
void f(T, T){};
int main() {
f(int{42},short{42});
}
Выше не удается скомпилировать. Почему? потому что даже если им разрешено конвертировать short в int без проблем (продвижение), они не относятся к одному типу.
Кроме того, поскольку nullptr
просто имеет несколько простой тип std::nullptr_t
- он совсем не подходит для участия в выводе аргументов шаблона.
Так что на мгновение забудьте о невыбранном контексте и попробуйте с выведенным:
template <class... T>
void g(S<T...>*, S<T...>* ) {}
int main() {
S<> s1;
g(&s1, nullptr);
}
или если вы предпочитаете просто
int main() {
S<> s1;
g(&s1, 0);
}
и оба не удаются по одной и той же причине.
Теперь, если вы хотите разрешить преобразование - тогда используйте шаблон удостоверения - и это работает даже для невосстановленного контекста!
Для вашего случая пример может выглядеть так (c++2a):
template <class... T>
void g(typename S<T...>::type, std::type_identity_t<S<T...> >*) {}
int main() {
f(42);
g(42, nullptr);
}
Который действителен. (обратите внимание, если у вас нет c++2a, просто напишите шаблон идентификации самостоятельно)
Как указано в комментарии, поворот вопроса может привести к более интересному вопросу?
В чем причина, позволяющая выводить аргументы пустых шаблонов в не выводимых контекстах?