简体   繁体   中英

Ambiguous call when recursively calling variadic template function overload

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?

In Function template overloading

There is lot of rules to tell which template function 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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM