短
转换函数operator int() 是由clang 选择而不是operator bool() const,因为b 不是const 限定的,而bool 的转换运算符是。
简短的推理是,在将b 转换为bool 时,用于重载解析的候选函数(带有隐式对象参数)是
operator bool (B2 const &);
operator int (B2 &);
第二个匹配更好,因为 b 不是 const 限定的。
如果两个函数共享相同的限定条件(const 或两者都不是),则选择 operator bool,因为它提供直接转换。
通过cast-notation转换,逐步分析
如果我们同意使用从b 转换为bool 我们可以深入研究这种转换。
1。演员表
b 到 bool 的转换
(bool)b
计算为
static_cast<bool>(b)
根据 C++11, 5.4/4 [expr.cast],因为 const_cast 不适用(此处不添加或删除 const)。
如果发明变量 t 的 bool t(b); 格式正确,则根据 C++11, 5.2.9/4 [expr.static.cast] 允许这种静态转换。
根据 C++11, 8.5/15 [dcl.init],此类语句称为直接初始化。
2。直接初始化bool t(b);
第 16 条提及最少的标准段落状态(强调我的):
初始化器的语义如下。目标类型是正在初始化的对象或引用的类型,源类型是初始化表达式的类型。
[...]
[...] 如果 源类型 是(可能是 cv 限定的)类类型,则考虑转换函数。
枚举适用的转换函数,并通过重载决议选择最佳的。
2.1 有哪些转换函数可用?
可用的转换函数是 operator int () 和 operator bool() const,因为 C++11, 12.3/5 [class.conv] 告诉我们:
派生类中的转换函数不会隐藏基类中的转换函数,除非这两个函数转换为相同的类型。
虽然C++11, 13.3.1.5/1 [over.match.conv] 声明:
考虑S及其基类的转换函数。
其中 S 是要转换的类。
2.2 哪些转换函数适用?
C++11, 13.3.1.5/1 [over.match.conv](强调我的):
1 [...] 假设“cv1 T”是被初始化对象的类型,“cv S”是初始化表达式的类型,其中 S 是类类型,候选函数的选择如下:
考虑了 S 及其基类的转换函数。那些不隐藏在 S 中并产生 T 类型或可以通过标准转换序列转换为 T 类型的类型的非显式转换函数是候选函数。
因此operator bool () const 是适用的,因为它没有隐藏在B2 中并产生bool。
最后一个标准引号中强调的部分与使用operator int () 的转换相关,因为int 是一种可以通过标准转换序列转换为bool 的类型。
从int 到bool 的转换甚至不是一个序列,而是一个简单的直接转换,这在 C++11, 4.12/1 [conv.bool]
中是允许的
算术、无作用域枚举、指针或指向成员类型的指针的纯右值可以转换为 bool 类型的纯右值。将零值、空指针值或空成员指针值转换为 false;任何其他值都将转换为 true。
这意味着operator int () 也适用。
2.3 选择了哪个转换函数?
通过重载决议(C++11, 13.3.1.5/1 [over.match.conv])选择合适的转换函数:
重载分辨率用于选择要调用的转换函数。
当涉及到类成员函数的重载决议时,有一个特殊的“怪癖”:隐式对象参数”。
每 C++11, 13.3.1 [over.match.funcs],
[...]静态和非静态成员函数都有一个隐式对象参数[...]
根据第 4 条,非静态成员函数的此参数的类型是:
其中 X 是函数所属的类,cv 是成员函数声明中的 cv 限定符。
这意味着(根据 C++11, 13.3.1.5/2 [over.match.conv]),在通过转换函数进行初始化时,
[t]参数列表有一个参数,即初始化表达式。 [ 注意:此参数将与转换函数的隐式对象参数进行比较。 ——尾注]
重载解析的候选函数是:
operator bool (B2 const &);
operator int (B2 &);
显然,如果使用B2 类型的非常量对象请求转换,operator int () 是更好的匹配,因为operator bool () 需要限定转换。
如果两个转换函数共享相同的 const 限定条件,则这些函数的重载决议将不再有效。
在这种情况下,转换(序列)排名就到位了。
3。当两个转换函数共享相同的 const 限定时,为什么选择 operator bool ()?
从B2 到bool 的转换是用户定义的转换序列(C++11, 13.3.3.1.2/1 [over.ics.user]) p>
用户定义的转换序列由初始标准转换序列、用户定义的转换和第二个标准转换序列组成。
[...] 如果用户定义的转换由转换函数指定,则初始标准转换序列会将源类型转换为转换函数的隐式对象参数。
C++11, 13.3.3.2/3 [over.ics.rank]
[...] 根据更好的转换序列和更好的转换之间的关系,定义了隐式转换序列的偏序。
[...] 用户定义的转换序列 U1 是比另一个用户定义的转换序列 U2 更好的转换序列,如果它们包含相同的用户定义的转换函数或构造函数或聚合初始化和 U1 的第二个标准转换序列优于U2的第二个标准转换序列。
operator bool() 的第二个标准转换是bool 到bool(身份转换),而operator int () 的第二个标准转换是int 到bool,这是一个布尔转换。
因此,使用operator bool () 的转换顺序如果两个转换函数共享相同的 const 限定符会更好。