问题
Consider this piece of code:
template<typename FirstArg>
void foo()
{
}
template<typename FirstArg, typename... RestOfArgs>
void foo()
{
foo<RestOfArgs...>();
}
int main()
{
foo<int, int, int>();
return 0;
}
It does not compile due to ambiguous call foo<RestOfArgs...>();
when RestOfArgs
has only one element ({int}
).
But this compiles without error:
template<typename FirstArg>
void foo(FirstArg x)
{
}
template<typename FirstArg, typename... RestOfArgs>
void foo(FirstArg x, RestOfArgs... y)
{
foo(y...);
}
int main()
{
foo<int, int, int>(5, 6, 7);
return 0;
}
Why is there ambiguity in the first case?
Why is there no ambiguity in the second case?
回答1:
In Function template overloading
There is lot of rules to tell which template functions is more specialized (according to given parameters).
The point which makes
template<typename> void foo();
template<typename, typename...> void foo();
ambiguous for foo<int>()
, but not
template<typename T> void foo(T);
template<typename T, typename... Ts> void foo(T, Ts...);
for foo(42)
is the following:
In case of a tie, if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack.
回答2:
Why is there ambiguity in the first case?
RestOfArgs
can be empty.
So foo<int>
can be instantiated as:
template<int>
void foo()
{
}
and
template<int,>
void foo()
{
foo<>();
}
both will compile, so it is ambiguous.
Actually foo<>()
won't compile, but it fails in the next instantiation, so it doesn't matter.
Why is there no ambiguity in the second case?
foo<int>(7)
can be instantiated as:
template<int>
void foo(int 7)
{
}
and
template<int>
void foo(int 7)
{
foo();
}
but the second one is an error, because there are no foo taking no argument, so the only candidate is the first one, so there won't be ambiguous
回答3:
The answer by @ZangMingJie answers the difference in behavior your are observing in your code.
I found it easier to understand the name resolution with the following change:
template<typename FirstArg>
void foo()
{
printf("1\n");
}
template<typename FirstArg, typename SecondArg, typename... RestOfArgs>
void foo()
{
printf("2\n");
foo<SecondArg, RestOfArgs...>();
}
int main()
{
foo<int, int, int>();
return 0;
}
When there are two or more template parameters are used, the second function gets invoked. When there is one template parameters, the first function gets invoked.
来源:https://stackoverflow.com/questions/42063084/ambiguous-call-when-recursively-calling-variadic-template-function-overload