在C ++中是否存在非短路逻辑“和”?

时间:2009-11-18 19:52:32

标签: c++ operators logical-operators

tl; dr:C ++中是否存在非短路逻辑AND(类似于&&)?

我有两个我想调用的函数,并使用返回值来计算第三个复合函数的返回值。问题是我总是希望评估这两个函数(因为它们输出有关系统状态的日志信息)

IE:

bool Func1(int x, int y){
  if( x > y){
    cout << "ERROR- X > Y" << endl;
  }
}
bool Func2(int z, int q){
  if( q * 3 < z){
    cout << "ERROR- Q < Z/3" << endl;
  }
}
bool Func3(int x, int y, int z, int q){
  return ( Func1(x, y) && Func2(z, q) );
}

当然,条件在函数中并不那么简单,是的,我意识到我可以使用临时变量来存储两个函数的返回值,然后对临时执行“短路”逻辑变量,但我想知道是否有一个“优雅”的语言解决方案,以保持Func3中的单行返回,同时仍然从两个函数获取日志消息。


回复摘要:

“按位”运算符|和&amp;可用于获得效果,但仅当返回类型为bool时。我在ANSI C ++规范中没有提到这一点。据我所知,这是有效的,因为“bool”转换为int(true = 1,false = 0),然后使用按位运算符,然后将其转换回bool。

也可以使用“+”和“*”运算符。这在ANSI C ++规范中没有提到,但可能因为与上述相同的原因而起作用。 “+”给“或”因为true被转换为1,然后0以外的任何东西都被转换回true。 “*”适用于“和”因为1(真)* 0(假)== 0(假)和1(真)* 1(真)== 1(真)

这两个似乎都依赖于隐式类型转换为整数然后再回到bool。这些都可能会破坏任何试图维护代码的人。

其他回答归结为“只使用临时”或“实施自己”,这不是问题。目标是查看是否已经在C ++标准中实现了运算符。

7 个答案:

答案 0 :(得分:32)

&运算符对bool个操作数执行逻辑“和”运算,并且不会被短路。

这不是一个序列点。您不能依赖于操作数的评估顺序。但是,保证两个操作数都被评估。

建议这样做。使用临时变量是更好的解决方案。不要牺牲“聪明代码”的可读性。

答案 1 :(得分:21)

  

是的,我意识到我可以使用临时变量来存储两个函数的返回值,然后对临时变量执行“短路”逻辑,但我想知道是否有“优雅”的语言解决方案保持Func3中的单行返回,同时仍然从两个函数获取日志消息。

这将是“优雅”的解决方案:)。依赖评估订单的副作用对于漫游到您项目中的下一位开发人员而言,远非优雅,容易出错,并且难以理解。当然,依赖于副作用与下面的代码段形成鲜明对比,这是一个完全合乎逻辑且有效的用例,仅依靠评估顺序:

if ( obj != NULL && obj->foo == blah ) { /* do stuff */ }

答案 2 :(得分:12)

是的,有内置的运营商这样做。 +执行非短路OR,*执行AND。

#include <iostream>
using namespace std;

void print(bool b)
{
    cout << boolalpha << b << endl;
}

int main() 
{
    print(true + false);
    print(true * false);
}

输出:

  

     

答案 3 :(得分:4)

你可以轻而易举地写自己的。

bool LongCircuitAnd( bool term1, bool term2 ) { return term1 && term2; }

bool Func3(int x, int y, int z, int q){
  return LongCircuitAnd( Func1(x,y), Func2(z,q) ); 

如果你想要非常喜欢,你甚至可以内联它!

好的,好的,如果你真的不想要调用函数的可怕开销。

bool Func3(int x, int y, int z, int q){
  return ((int)Func1(x,y)) * ((int)Func2(z,q)); 

但我不认为那么优雅。可以想象,过于智能的编译器可能会使这个短路...

答案 4 :(得分:3)

如果要使用临时变量,但保持返回单个语句,可以使用逗号运算符:

return (b1=Func1()), (b2=Func2()), (b1&&b2);

逗号运算符强制执行一个序列点,因此每个运算符都会计算其左操作数,丢弃结果,然后计算其右操作数。

另一种可能性,但我倾向于建议反对,将是两个函数返回一个超过'&amp;&amp;'的类型运营商。由于重载运算符调用一个函数,它总是会计算两个操作数,即使在内置运算符没有的情况下(例如&amp;&amp;) - 通常这是一个问题,但在这种情况正是你想要的:

class mybool { 
    bool value;
public:
    bool operator&&(mybool const &other) const { 
        return value && other.value;
    }
};

mybool Func1(int, int);
mybool Func2(int, int);

bool Func3(int x, int y, int z, int q) { 
    return Func1(x, y) && Func2(z,q);
}

虽然这有效,但在我看来,它似乎有点过于“聪明” - 这对大多数读者来说根本不是显而易见的。 mybool的另一个名称可能会有所帮助,但是我不能想到一个能够很好地反映意图的名称而不会变得如此冗长,这将是一个净损失。

答案 5 :(得分:2)

是。 operator&&operator||的重载版本不会短路 - 即使左手操作数“确定”结果,它们也会评估两个操作数...(Source

话虽如此,不要重载operator&&operator||。对于会查看&&||并假设它们发生短路的维护程序员,请保持良好状态。

答案 6 :(得分:2)

为了这个目的,引入了一个近乎普遍但通常没有文档记录的非标准运算符,由GCC和x ?: y一起开创(x,如果非零则为y),现在遗憾地删除了>?<? min / max运算符及其复合赋值表单(请参阅http://gcc.gnu.org/onlinedocs/gcc/Deprecated-Features.html)。可悲的是,在&&&已经被使用的情况下,他们似乎一直在刮取枪管的底部以找到合适的角色序列,但这只是我的意见 - 欢迎任何历史解释为什么这个可能已被选中。

所以,虽然它目前并不像许多其他运营商那样众所周知,但 >!运算符(正确但又无聊地称为“长路和”,但通俗地称为“更大的结”)大多数C和C ++编译器(包括GCC甚至MSVC ++)都添加了知识中的那些,以满足这一要求:

bool f1() { ... }
bool f2() { ... }

...
bool f3() { return f1() >! f2(); }

请自己动手; - )。

相关问题