有时可以获取重载函数模板的地址

gd1*_*gd1 8 c++ templates language-lawyer overload-resolution

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;
}
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,有关为何可以采取地址的任何线索?

Bar*_*rry 3

的推导auto与模板推导相同。来自[dcl.spec.auto]:

\n\n
\n

当使用占位符类型声明的变量被初始化时,[...],推导的返回类型或变量类型是根据其初始值设定项的类型确定的。如果占位符是自动类型说明符,\n 则使用模板参数推导规则确定推导类型。如果占位符是auto 类型说明符,\n 则使用模板参数推导规则确定推导类型。

\n
\n\n

所以当我们有以下任一情况时:

\n\n
auto f = foo<A>;\nauto b = bar<A>;\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们正在执行类型推导,就像我们调用一样(借用 TC 的用词):

\n\n
template <typename M> void meow(M );\nmeow(foo<A> );\nmeow(bar<A> );\n
Run Code Online (Sandbox Code Playgroud)\n\n

并分别使用推导的类型作为和M的类型。fb

\n\n

但是,根据 [temp.deduct.type],我的重点是:

\n\n
\n

如果模板参数仅在非推导上下文中使用并且未显式指定,则模板参数推导将失败。

\n\n

非推导上下文为:
\n \xe2\x80\x94 [...]
\n \xe2\x80\x94 无法进行参数推导的函数参数,因为关联的函数\n 参数是函数,或者一组重载函数(13.4),并且适用以下一个或多个:
\n \xe2\x80\x94多个函数与函数参数类型匹配(导致不明确的推导)、\n 或
\n \xe2 \x80\x94 没有函数与函数参数类型匹配,或者
\n \xe2\x80\x94 作为参数提供的函数集包含一个或多个函数模板。
\n \xe2\x80\x94 [...]

\n
\n\n

在这两种情况下,参数都是一组重载函数,其中包含一个或多个函数模板 - 这使其成为非推导上下文,因此模板参数推导失败。因此,clang 拒绝这两个初始化是正确的。

\n