Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Taking the address of an overloaded function template is possible, sometimes

On gcc 4.9.0:

#include <iostream>
#include <map>

struct A
{
    typedef int type;
};

template<typename T> void foo(T*) { std::cout << "a" << std::endl; }
template<typename T> void foo(typename T::type*) { std::cout << "b" << std::endl; }

template<typename T>
struct identity
{
    typedef T type;
};

template<typename T> void bar(T*) { std::cout << "a" << std::endl; }
template<typename T> void bar(typename identity<T>::type*) { std::cout << "b" << std::endl; }

int main()
{
    //auto f = foo<A>; // ambiguous
    foo<A>(0); // prints "b", as the second overload is more specific

    auto b = bar<A>; // fine
    bar<A>(0); // prints "b", as the second overload is more specific (?)
    b(0); // prints "b"

    return 0;
}

Any clue on why the address can be taken, in the second case?

like image 872
gd1 Avatar asked Jul 13 '15 19:07

gd1


1 Answers

The deduction for auto is the same as template deduction. From [dcl.spec.auto]:

When a variable declared using a placeholder type is initialized, [...], the deduced return type or variable type is determined from the type of its initializer. If the placeholder is the auto type-specifier, the deduced type is determined using the rules for template argument deduction. If the placeholder is the auto type-specifier, the deduced type is determined using the rules for template argument deduction.

So when we have either:

auto f = foo<A>;
auto b = bar<A>;

We are performing type deduction as if we called (to borrow T.C.'s choice of words):

template <typename M> void meow(M );
meow(foo<A> );
meow(bar<A> );

and using the deduced type M as the type of f and b, respectively.

But, according to [temp.deduct.type], emphasis mine:

If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

The non-deduced contexts are:
— [...]
— A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply:
    — more than one function matches the function parameter type (resulting in an ambiguous deduction), or
    — no function matches the function parameter type, or
    — the set of functions supplied as an argument contains one or more function templates.
— [...]

In both cases, the argument is a set of overloaded functions which contains one or more function templates - which makes it a non-deduced context, so template argument deduction fails. Thus, clang is correct in rejecting both initializations.

like image 84
Barry Avatar answered Nov 06 '22 10:11

Barry