您可以在David Vandvooorde和Nicolai Josuttis的《C++模板完整指南》一书的附录B中找到以下文本。
B.2简化的过载分辨率
考虑到第一个原则,我们只需要指定给定的参数与可行的对应参数匹配候选人作为第一个近似值,我们可以对可能的匹配进行排序如下(从最好到最坏):
- 完美匹配。参数具有表达式的类型,或者其类型是对表达式类型的引用(可能添加了const和/或volatile限定符)
- 配合细微的调整。例如,这包括数组变量到指向其第一个元素的指针的衰减,或者添加const以将类型为int**的参数与类型为键入int const*const*
- 与晋升相匹配。Promotion是一种隐式转换,包括对小积分类型(如bool,char、short,有时还有枚举)转换为int、unsigned int、long或unsigned long,以及float到double的转换
- 仅与标准转换匹配。这包括任何类型的标准转换(如int到float),但不包括隐式调用转换运算符或转换构造函数
- 与用户定义的转换匹配。这允许任何类型的隐式转换
- 与省略号匹配。省略号参数几乎可以匹配任何类型(但非POD类类型会导致未定义的行为)
几页后,本书显示了以下示例和文本(强调我的):
class BadString {
public:
BadString(char const*);
...
// character access through subscripting:
char& operator[] (size_t); // (1)
char const& operator[] (size_t) const;
// implicit conversion to null-terminated byte string:
operator char* (); // (2)
operator char const* ();
...
};
int main()
{
BadString str("correkt");
str[5] = 'c'; // possibly an overload resolution ambiguity!
}
一开始,str[5]这个表达式似乎没有任何歧义。这个(1)处的下标运算符看起来是完全匹配的。然而不太完美,因为参数5的类型为int运算符需要一个无符号整数类型(size_t和std::size_t通常具有unsigned int或unsigned long类型,但从不具有int类型)。尽管如此,一个简单的标准整数转换使得(1)很容易实现。然而,还有另一个可行的候选者:内置下标操作人员事实上,如果我们将隐式转换运算符应用于str(这是隐式成员函数参数),我们获得一个指针类型,现在应用内置的下标运算符。此内置运算符采用ptrdifft类型的参数,在许多平台上相当于int,因此与参数完全匹配5.因此,即使内置的下标运算符(通过用户定义的转换)与隐含参数匹配不佳,它也是更好的与在(1)处为实际下标定义的运算符相匹配因此潜在的歧义。
请注意,第一个列表是简化的过载解决方案。
为了消除关于int
是否与ptrdiff_t
相同的"可能"one_answers"潜在",让我们更改一行:
str[(ptrdiff_t)5] = 'c'; // definitely an overload resolution ambiguity!
现在我从g++
得到的消息是:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default]
并且CCD_ 5将该警告提升为错误。
因此,在不深入标准的情况下,这告诉你,简化列表只是故事的一部分。这个列表告诉你从A到B时更喜欢几条可能的路线中的哪一条,但它并没有告诉你是喜欢从A到B的旅行还是喜欢从C到D的旅行
你可以在这里更明显地看到同样的现象(和同样的g++消息):
struct S {
explicit S(int) {}
operator int() { return 0; }
};
void foo(const S&, long) { }
void foo(int, int) { }
int main() {
S s(0);
foo(s, 1);
}
同样,对foo
的调用是不明确的,因为当我们可以选择隐式转换哪个参数来选择重载时,规则不会说"选择两者中更轻量级的转换,并转换需要该转换的参数"。
现在你要问我标准引文,但我会以我需要抓紧时间为借口不查;-)
总之,这里的"用户定义的转换比标准整数转换更匹配"不是真的。然而,在这种情况下,标准将两个可能的重载定义为同等好,因此调用是不明确的。
str.operator[](size_t(5));
以明确的方式编写代码,您将不需要为所有这些事情烦恼:)还有很多事情要做。