C++ 为什么到引用的转换会干扰到到bool的转换?

C++ 为什么到引用的转换会干扰到到bool的转换?,c++,C++,如果我有一个到引用的转换操作符,那么这个操作符将优先于到bool的转换。为什么会发生这种情况,我如何修复它 (如果重要的话,我使用的是GCC 4.5。我在ideone上验证了GCC-4.7.2中也发现了相同的行为。) 假设如下: class B { protected: const int a_; int b_; B (int b, int a) : a_(a), b_(b) {} public: operator bool () const { return b

如果我有一个到引用的转换操作符,那么这个操作符将优先于到
bool
的转换。为什么会发生这种情况,我如何修复它

(如果重要的话,我使用的是GCC 4.5。我在ideone上验证了GCC-4.7.2中也发现了相同的行为。)

假设如下:

class B {
protected:
    const int a_;
    int b_;
    B (int b, int a) : a_(a), b_(b) {}
public:
    operator bool () const { return b_ == a_; }
};

class D1 : public B {
public:
    D1 (int b = 0, int a = 0) : B(b, a) {}
    operator int () const { return b_; }
};

class D2 : public B {
public:
    D2 (int b = 0, int a = 0) : B(b, a) {}
    operator int & () { return b_; }
};
然后,假设它们用于以下简单程序:

int main () {
    if (D1 d1a = D1('a', 'a')) std::cout << "d1a\n";
    if (D1 d1b = D1('b', 'a')) std::cout << "d1b\n";
    if (D2 d2a = D2('a', 'a')) std::cout << "d2a\n";
    if (D2 d2b = D2('b', 'a')) std::cout << "d2b\n";
    return 0;
}
请注意,
d1b
不在输出中,这意味着对
bool
的转换按照我对
D1
的预期方式进行。但是,对于
D2
,到引用类型的转换似乎优先于
bool
转换。为什么会这样?是否可以对
D2
进行简单更改,以允许
bool
转换优先于
if
检查

目前,我正在使用
D1
并向其添加赋值运算符以实现引用的行为。

D1 d1a = D1('a', 'a');
D1 d1b = D1('b', 'a');
D2 d2a = D2('a', 'a');
D2 d2b = D2('b', 'a');
if (d1a) std::cout << "d1a\n";
if (d1b) std::cout << "d1b\n";
if (d2a) std::cout << "d2a\n";
if (d2b) std::cout << "d2b\n";

实际上,它与
int&
无关,而是
const
-ness的问题:

operator bool () const { return b_ == a_; }
              /* ^^^^^ */
              /* vvvvv */
operator int & () { return b_; }
d2a
D2
,而不是
const D2
,因此非const转换运算符更适合。如果你把它写成

operator const int & () const { return b_; }
您将获得预期的行为,请参阅

请注意,
运算符const int&
不会干扰,即使您使用对象的
const
版本,以下几行仍然会导致您的预期行为(请参阅):


如果(常数d1d1a=D1('a','a'))std::cout,则结果相同(请参阅)。我会更新这个问题。好吧,好吧。。。MSVC++11(VS12)不打印
d2b
+1,我发现GCC-C++和MSVC++之间的行为差异很有趣。非常有趣的是,GCC似乎更喜欢生成转换序列的更好的“直接重载解析”,而不是提供与异常cv限定符完全匹配的另一个转换函数…:)谢谢,这就为我解释了。解决方法是添加一个非
const
版本的
bool
转换操作符。是的,我同意我自己可能已经发现了这一点,但是除了因为我过了糟糕的一天而惩罚我之外,还有什么更重要的理由让我投反对票吗?
if (D2 d2a = D2('a', 'a')) std::cout << "d2a\n";
if (D2 d2a = D2('b', 'a')) std::cout << "d2b\n";
if (D2 d2b = D2('b', 'a')) std::cout << "d2b\n";
operator bool () const { return b_ == a_; }
              /* ^^^^^ */
              /* vvvvv */
operator int & () { return b_; }
operator const int & () const { return b_; }
if (const D1 d1a = D1('a', 'a')) std::cout << "d1a\n";
if (const D1 d1b = D1('b', 'a')) std::cout << "d1b\n";
if (const D2 d2a = D2('a', 'a')) std::cout << "d2a\n";
if (const D2 d2b = D2('b', 'a')) std::cout << "d2b\n";