Search code examples
c++templatesc++17overload-resolution

Why isn't a call to overloaded function template ambiguous?


Consider the following example. There are two function templates on lines marked (1) and (2) which get called on line (3). Both templates match the call, and it seems that none of them is more specialized than the other.

#include <utility>

template <int V, bool Enabled = true>
struct Version;

template <int V>
std::true_type  Database(Version<V, V == 1>*);  // (1)

template <int V>
std::false_type Database(Version<V>*);          // (2)

using Winner = decltype(Database(std::declval<Version<1>*>()));  // (3)

int foo()
{
    return Winner::value;
}

Naturally, I would expect line (3) to produce an 'ambiguous call' error. But it doesn't. gcc 13.2, clang 15.0 and msvc v19.37 all select overload (2) with no error. Here's godbolt online example.

The question is: why? What am I missing in partial ordering and overload resolution?


Solution

  • Function_template_overloading is complicated, with transformation with Parameter/Argument.

    template <int V>
    std::true_type  Database(Version<V, V == 1>*);  // #1
    
    template <int V>
    std::false_type Database(Version<V>*);          // #2
    
    
    Database(std::declval<Version<1>*>()); // deduction for #1 [V=1]
                                           // deduction for #2 [V=1] 
    // partial ordering:
     
    
    // #1 from #2: Version<V, B> from Version<U, true>: P1=V, A1=U: V=U
    //                                            P2=B, A2=true: B=true OK
     
    // #2 from #1: Version<V, true> from Version<U, B2>: P1=V A1=U: V=U
    //                                             P2=true A2=B2: fails
     
    // #2 is more specialized than #1