Первый MCVE:
template<typename T, typename... Tail>
void f(T head, Tail... tail) {
f(tail...); // tr y again with tail
}
f(1, 2, 3);
Теперь создайте экземпляр:
f<int, int, int>(1, 2, 3);
компилируется в:
template<T = int, Tail...={int,int}>
void f(int head, int tail0, int tail1) {
f(tail0, tail1); // tr y again with tail
}
Рекурсивный вызов:
f<int,int>(tail0, tail1); // tr y again with tail
, который компилируется в:
template<T = int, Tail...={int}>
void f(int head, int tail0) {
f(tail0); // tr y again with tail
}
рекурсивный вызов разрешается в:
f<int>(tail0); // tr y again with tail
, который компилируется в:
template<T = int, Tail...={}>
void f(int head) {
f(); // tr y again with tail
}
и здесь мы пытаемся позвонить f()
.
Нет действительного вызова f()
видимым, поэтому вы получаете сообщение об ошибке.
A void f() {}
в вызов f()
здесь не помогает, потому что в шаблоне поиск выполняется до того, как f()
станет видимым.
Если вы хотите исправить это простым способом, вы можете добавить inline void f(){}
над шаблоном f
.
Чем сложнее путь?
template<class...Ts>
void f(Ts...ts) {
using discard=int[];
(void)discard{ 0, ( void(
g(ts)
),0)...};
}
, который также устраняет рекурсию. Или в c ++ 17 :
template<class...Ts>
void f(Ts...ts) {
( (void)(g(ts)), ... );
}
это также быстрее компилируется, так как создает намного меньше (и короче) символов.