在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;
}
在第二种情况下,为什么地址可以的任何线索?
答案 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
作为f
和b
的类型。
但是,根据[temp.deduct.type],强调我的:
如果模板参数仅在非推导中使用 上下文并没有明确指定,模板参数推断失败。
未推断的背景是:
- [...]
- 由于关联函数而无法进行参数推导的函数参数 参数是一个函数,或一组重载函数(13.4),并且以下一个或多个适用:
- 多个函数匹配函数参数类型(导致模糊推理), 或
- 没有函数匹配函数参数类型或
- 作为参数提供的函数集包含一个或多个函数模板 - [...]
在这两种情况下,参数都是一组重载函数,它们包含一个或多个函数模板 - 这使得它成为非推导的上下文,因此模板参数推导失败。因此,clang在拒绝两次初始化时都是正确的。