Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguous overload - partial function template ordering with parameter packs

Consider the following contrived piece of code:

template <class... > struct pack { };

template <class R, class T, class... Args>
int foo(pack<T>, Args...)
{
    return sizeof(R);
}

template <class R, class T, class... Ts, class... Args>
int foo(pack<T, Ts...>, Args... args)
{
    return foo<T>(pack<Ts...>{}, args...);
}

int main() {
    // gcc: OK, clang: ambiguous
    foo<int>(pack<int>{});

    // gcc: ambiguous, clang: ambiguous
    foo<int>(pack<int>{}, 0);
}

Both gcc and clang accept both calls if the 2nd overload is changed to take a pack of at least 2 types instead of a pack of at least one type:

template <class R, class T, class T2, class... Ts, class... Args>
int foo(pack<T, T2, Ts...>, Args... args)
{
    return foo<T>(pack<T2, Ts...>{}, args...);
}

If the non-deduced template parameter is moved to a deduced template parameter, then:

template <class... > struct pack { };

template <class R, class T, class... Args>
int foo(pack<R>, pack<T>, Args...)
{
    return sizeof(R);
}

template <class R, class T, class... Ts, class... Args>
int foo(pack<R>, pack<T, Ts...>, Args... args)
{
    return foo(pack<T>{}, pack<Ts...>{}, args...);
}

int main() {
    // gcc ok with both, clang rejects both as ambiguous
    foo(pack<int>{}, pack<int>{});
    foo(pack<int>{}, pack<int>{}, 0);
}

I'd expect all the calls to be OK in every version of this. What is the expected outcome of the above code examples?

like image 442
Barry Avatar asked Dec 08 '16 19:12

Barry


People also ask

What is ambiguity in function overloading?

In Function overloading, sometimes a situation can occur when the compiler is unable to choose between two correctly overloaded functions. This situation is said to be ambiguous. Ambiguous statements are error-generating statements and the programs containing ambiguity will not compile. Automatic type conversions are the main cause of ambiguity.

Why is the Order of the templates partial?

The ordering is partial because there can be some templates that are considered equally specialized. The compiler chooses the most specialized template function available from the possible matches.

What does error call of overloaded test (float) is ambiguous mean?

prog.cpp:25:12: error: call of overloaded ‘test (float)’ is ambiguous The above code will throw an error because the test (2.5f) function call will look for float function if not present it is only promoted to double, but there is no function definition with double or float type of parameter.

What is function template overloading?

………. …… ….. ……. where, T is template argument accepting different arguments and class is a keyword. The name of the function templates are the same but called with different arguments is known as function template overloading.


1 Answers

I believe now that clang is correct to reject and gcc is incorrect to accept those forms that it does. Here's a simplified example:

template <class...> struct pack { };

// (1)
template <class T>
void foo(pack<T> ) { }

// (2)
template <class T, class... Ts>
void foo(pack<T, Ts...> ) { }

int main() {
    foo(pack<int>{});
}

Both overloads are valid, and deducing (2) from (1) succeeds straightforwardly. The only issue is can we deduce (1) from (2). I'd initially think no... But [temp.deduct.type]/9 states:

If P has a form that contains <T> or <i>, then each argument Pi of the respective template argument list of P is compared with the corresponding argument Ai of the corresponding template argument list of A. [...] During partial ordering (14.8.2.4), if Ai was originally a pack expansion:
— if P does not contain a template argument corresponding to Ai then Ai is ignored;

So when we synthesize types for <T, Ts...> (say <U, Xs...>), we deduce T=U and then there is no template argument corresponding to the pack expension Xs..., so we ignore it. All the non-ignored template parameters succeeded in template deduction, so we consider deducing (1) from (2) to be success.

Since deduction succeeds in both directions, neither function template is considered more specialized than the other, and the call should be ambiguous.


I have not yet submitted a bug report, waiting on some confirmation from the community.

like image 178
Barry Avatar answered Oct 19 '22 07:10

Barry