I don't understand how this is ambiguous -- A is a declaration and B
is a definition of the function declared by A. Right?
No. A is a declaration of a function template, and B is a declaration (and definition) of another function template.
The compiler has no way to decide between the two: they both have no arguments, and the template arguments are a match for both.
The one in the middle is an explicit total specialization of the function template declared in A.
If you tried to make B another specialization of A:
template <typename H, typename... T> /* B */
size_t num_args<H, T...>()
{
return 1 + num_args <T...> ();
}
... you'd end up with a partial specialization of a function template, which is not allowed.
You can do this with the usual trick of using a class template with partial specializations and a function template that calls into the class template:
template <typename... T>
class Num_Args;
template <>
struct Num_Args <>
{
static constexpr size_t calculate() {
return 0;
}
};
template <typename H, typename... T>
struct Num_Args <H, T...>
{
static constexpr size_t calculate() {
return 1 + Num_Args<T...>::calculate();
}
};
template <typename... T> /* B */
constexpr size_t num_args ()
{
return Num_Args<T...>::calculate();
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…