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

时间:2015-07-13 19:40:47

标签: 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;
}

在第二种情况下,为什么地址可以的任何线索?

1 个答案:

答案 0 :(得分:3)

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

  

当初始化使用占位符类型声明的变量时,推导出的返回类型或变量类型为   根据其初始化程序的类型确定。如果占位符是自动类型说明符,   推导出的类型是使用模板参数推导的规则确定的。如果占位符是auto 类型说明符,   推导出的类型是使用模板参数推导的规则确定的。

所以当我们有:

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

我们正在进行类型扣除,好像我们打电话一样(借用T.C.的选择):

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

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

但是,根据[temp.deduct.type],强调我的:

  

如果模板参数仅在非推导中使用   上下文并没有明确指定,模板参数推断失败。

     

未推断的背景是:
   - [...]
   - 由于关联函数而无法进行参数推导的函数参数   参数是一个函数,或一组重载函数(13.4),并且以下一个或多个适用:
   - 多个函数匹配函数参数类型(导致模糊推理),   或
   - 没有函数匹配函数参数类型或
   - 作为参数提供的函数集包含一个或多个函数模板    - [...]

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