【问题标题】:Is it compiler bug or my bug when using boost::tribool in a conditional?在条件中使用 boost::tribool 时是编译器错误还是我的错误?
【发布时间】:2025-12-28 05:00:12
【问题描述】:

代码如下: (Coliru Code)

#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <boost/logic/tribool.hpp>

struct B
{
  boost::tribool boo;

  void bug ()
  {
    bool tmp = indeterminate (boo);
    std::cout << "tmp = " << std::boolalpha << tmp << "\n";
    if (tmp && (boo = should_not_be_called ()) == false) {;}
  }

  bool should_not_be_called () const
  {
    std::cout << "BUG, wrong call\n";
    abort ();
  }
};

int main ()
{
  B a;
  a.bug ();
}

输出是

tmp = false
BUG, wrong call
bash: line 7: 14410 Aborted                 (core dumped) ./a.out

我不明白为什么在这里调用 should_not_be_call。测试的编译器是 gcc 4.9 和 clang 3.6。

更新:

我阅读了答案并将带有“if”的行更改为

if (tmp && (false == (boo = should_not_be_called ()))) {;}

(Coliru)

现在 && 运算符两边都有纯布尔类型,但我仍然遇到同样的错误。为什么?

【问题讨论】:

  • 我当地的博彩公司提供的赔率为 1000:1,这是一个编译器错误。
  • 在这里回答,我想:*.com/questions/628526/…
  • @NikkiChumakov 不,运算符== 也超载了。 bool &amp;&amp; (bool == tribool) 将解析为 bool &amp;&amp; tribool,这将再次调用重载运算符而不是短路

标签: c++


【解决方案1】:

编译器在右边。让我们分析一下你的两个ifs中涉及的类型,同时考虑到所有operator overloads that boost::tribool provides

if (tmp && (boo = should_not_be_called ()) == false) {;}

if (bool && (tribool = bool) == bool) {;} // = is overloaded to return tribool
if (bool && tribool == bool) {;} // == is overloaded to return tribool
if (bool && tribool) {;} // && is overloaded

还有第二个if

if (tmp && (false == (boo = should_not_be_called ()))) {;}

if (bool && (bool == (tribool = bool))) {;} // = is overloaded to return tribool
if (bool && (bool == tribool)) {;} // == is overloaded to return tribool
if (bool && tribool) {;} // && is overloaded

在这两种情况下,我们都会得到一个重载的operator &amp;&amp;。运算符重载是不尊重内置运算符的特殊调用行为的函数。也就是说,用户重载的&amp;&amp;|| 不会短路,, 的用户重载保证操作数评估顺序。这三个都以未指定的顺序评估所有操作数,就像任何其他函数调用一样。

这正是强烈建议不要重载&amp;&amp;||, 的原因,如果您希望它们表示“和”、“或”和“序列”之类的意思。


摘录问题的原文:

编译器在右边。 boost::tribool重载opeator !,即&amp;&amp;的操作数类型为boolboost::triboolboost::tribool 还为这些参数类型重载了 operator &amp;&amp;,因此会调用此重载。

【讨论】:

  • @NikkiChumakov:不,&amp;&amp; 的左边是tmp,也就是boost::tribool。也许你的意思是if(tmp==true &amp;&amp; (boo=should_not_be_called())==false)
  • 重载, 是我今天学到的最糟糕的事情。
  • 对我来说,整个事情看起来像是标准缺陷,如果运算符重载可能会改变评估顺序和短路。语言不应该这样设计。
  • 您能稍微修改一下您的答案吗? OP 修改了问题以从代码中删除 operator !,所以现在你的答案对于不检查问题历史的人来说似乎有点混乱。另外,, 的“短路”是指它的有序评估吗?因为它并没有真正“短路”(至少在谈论&amp;&amp;|| 时不是同一个词)。 (尽管总而言之,很好的答案!)
  • @NikkiChumakov 你是对的,这正是它的意思,但是如果有一个用户不会期望短路行为的用途,那么重载运算符禁用短路不是问题。 Boost Spirit makes clever use of an overloaded operator|| that users will expect not to short-circuit.
【解决方案2】:

boost::tribool 中的逻辑运算符如 HERE 所述被重载,因此与 c++ 的内置逻辑运算符不同,逻辑运算符的从左到右求值未应用,并且没有短路,因此操作数的求值仍然存在未指定。

【讨论】:

  • 我认为您使用 ACM 徽标作为您的个人资料图片具有误导性,因为我怀疑您是在为 ACM 工作或代表 ACM 发帖。
  • @Gabriel 更不用说根据ACM identity standards,使用不带文字标记的“ACM Diamond”是“需要 ACM 批准”