这是如何避免从“double”到“int”的隐式转换?的后续问题。假设我有以下代码:
template <class T>
struct wrapper {
wrapper(const T&);
};
void f(wrapper<int>);
void f(wrapper<double>);
int main () {
f(1); // error: ambiguous call to overloaded function
}
参见编译器浏览器中的实时示例;请注意,所有主要编译器的行为都是相同的
怎么
f(1)
有歧义?有两种转换顺序:
1
-> const int&
通过限定转换和引用绑定 -> wrapper<int>
通过转换构造函数1
-> const double&
通过浮点转换、临时物化、限定转换和引用绑定 -> wrapper<double>
通过转换构造函数第一个转换序列看起来更好,那么为什么第一个重载没有获胜呢?
整个隐式转换序列由用户定义的转换序列组成:
格式良好的隐式转换序列是以下形式之一:
用户定义的转换序列由初始标准转换序列、用户定义的转换和第二个标准转换序列组成。
标准转换顺序
int -> const int&
比int -> const double&
好,但是,没有考虑这一点。用户定义的转换序列 int -> wrapper<int>
和 int -> wrapper<double>
均按 [over.ics.rank] p2 排名,用户定义的转换序列之间的唯一区别在 [over.ics.rank] p3.3 仅适用于 second 标准转换。
与直觉相反:
wrapper<int> -> int -> const int&
具有
wrapper<double> -> double -> const int&
转换功能,转换
wrapper<T>
会比 operator T
更好。int -> const int& -> wrapper<int>
和 int -> const double& -> wrapper<double>
的排名相同。这有效:
template <class T>
struct wrapper {
wrapper(const T&);
};
void f(wrapper<int>);
void f(wrapper<double>);
int main () {
f(wrapper<double>(1.0));
f(wrapper<int>(1));
}