Рассмотрим следующие примеры (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...
пусто после попытки и неудачи удержания.
- Это поведение предназначено? Если так, почему?
- Если да, то предполагалось ли, что формулировка "не выводится иначе" определяет это поведение? (т.е. это означает, что пустой запасной вариант возникает только в том случае, если пакет отображается без выводимых контекстов)
- Если да, достаточно ли ясна эта формулировка? Кажется правдоподобным альтернативное прочтение слова "не выведено иначе": "либо дедукция не была сделана, либо попытка дедукции была неудачной".