【问题标题】:Why does conversion to reference interfere with conversion to bool?为什么转换为参考会干扰转换为布尔值?
【发布时间】:2013-07-11 21:40:58
【问题描述】:

如果我有一个引用的转换运算符,这个运算符将优先于转换为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;
}

这个程序的输出是:

d1a
d2a
d2b

请注意d1b 不在输出中,这意味着转换为bool 的工作方式与我对D1 的预期相同。但是,对于D2,似乎转换为引用类型优先于bool 转换。为什么会这样?我可以对D2 进行简单的更改以允许bool 转换在if 检查中优先吗?

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

【问题讨论】:

  • 嗯,是的,我同意我自己可能应该能够发现这一点,但是除了因为我今天过得不好而惩罚我之外,还有更重要的理由来否决投票吗?

标签: c++


【解决方案1】:

其实和int&amp;无关,是const-ness的问题:

operator bool () const { return b_ == a_; }
              /* ^^^^^ */
              /* vvvvv */
operator int & () { return b_; }

d2aD2,而不是const D2,因此非常量转换运算符更合适。如果你写成

operator const int & () const { return b_; }

您将获得预期的行为,请参阅http://ideone.com/vPPPYV

请注意,即使您使用对象的const 版本,operator const int&amp; 也不会干扰,以下行仍会导致您的预期行为(请参阅http://ideone.com/DTE0xH):

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";

【讨论】:

  • 谢谢,这为我解释了。解决方法是添加bool 转换运算符的非const 版本。
【解决方案2】:

这个

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";

打印

d1a
d2a

对我来说。

你有

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

如果您在这两种情况下不使用相同的名称会怎样? 如果我将第 4 个替换为

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

【讨论】:

  • 结果是一样的(见ideone.com/CpPXZS)。我会更新问题。
  • 好吧,好吧 ... MSVC++11 (VS12) 不打印d2b
  • +1,我发现 GCC-C++ 和 MSVC++ 之间的行为差​​异很有趣。
  • 有趣的是,GCC 似乎更喜欢 更好 “直接重载解决方案”,它产生一个转换序列,而不是另一个提供与异常 cv 限定符精确匹配的转换函数... :)
猜你喜欢
  • 2013-11-12
  • 2021-06-27
  • 2014-03-16
  • 2011-12-26
  • 1970-01-01
  • 2016-02-27
  • 2018-07-11
  • 2013-11-22
  • 2016-04-27
相关资源
最近更新 更多