代码如下: (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_called。测试的编译器是gcc 4.9和clang 3.6。
更新:
我阅读了答案并用&#34更改了行;如果&#34;到
if (tmp && (false == (boo = should_not_be_called ()))) {;}
(Coliru)
现在&amp;&amp;&amp;&amp;运营商,但我仍然有同样的错误。为什么呢?
答案 0 :(得分:15)
编译器在右边。让我们分析两个if
中涉及的类型,并考虑所有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 &&
。运算符重载是不考虑内置运算符的特殊调用行为的函数。也就是说,用户重载&&
,||
执行不短路,,
的用户重载不保证操作数评估顺序。所有三个都以未指定的顺序评估所有操作数,就像任何其他函数调用一样。
这正是强烈建议不要超载&&
,||
或,
的原因,如果您希望它们意味着“和”,“或”等“序列”。
摘录问题原文:
编译器在右边。 boost::tribool
重载opeator !
,这意味着&&
的操作数类型为bool
和boost::tribool
。 boost::tribool
也会为这些参数类型重载operator &&
,因此会调用此重载。
答案 1 :(得分:4)
boost :: tribool中的逻辑运算符如上所述HERE重载,因此与c ++的内置逻辑运算符不同,逻辑运算符的从左到右的评估不适用且没有短路因此评估操作数仍未指定。