Рассмотрим следующие примеры (Coliru link):
template <class... T> struct S { using type = int; };
template <class... T>
void f(typename S<T...>::type) {
static_assert(sizeof...(T) == 0);
}
template <class... T>
void g(typename S<T...>::type, S<T...>*) {}
int main() {
f(42);
g(42, nullptr);
}
GCC и Clang оба довольны звонком в f, но не звонком в g.
В вызове к f, хотя T... появляется в невыбранном контексте, в конечном итоге он выводится как пустой. Похоже, это связано с [temp.arg.explicit]/4:
... Пакет параметров конечного шаблона ([temp.variadic]), не выведенный иначе, будет выведен как пустая последовательность аргументов шаблона....
Однако в обращении к g тот факт, что T... дополнительно появляется в выводимом контексте, что приводит к попытке выведения и неудаче, кажется, приводит к тому, что g становится нежизнеспособным. Похоже, что "отступление" к T... пусто после попытки и неудачи удержания.
- Это поведение предназначено? Если так, почему?
- Если да, то предполагалось ли, что формулировка "не выводится иначе" определяет это поведение? (т.е. это означает, что пустой запасной вариант возникает только в том случае, если пакет отображается без выводимых контекстов)
- Если да, достаточно ли ясна эта формулировка? Кажется правдоподобным альтернативное прочтение слова "не выведено иначе": "либо дедукция не была сделана, либо попытка дедукции была неудачной".