34

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

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

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 中保持单行返回,同时仍然从两个函数中获取日志消息。


回复摘要:

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

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

这两者似乎都依赖于隐式类型转换为整数然后返回布尔。这两者都可能会搞砸任何试图维护代码的人。

其他回答归结为“只使用临时人员”或“实施你自己的”,这不是问题。目标是查看是否已经在 C++ 标准中实现了一个运算符来执行此操作。

4

7 回答 7

37

运算符对操作数&执行逻辑“与”bool运算并且不短路。

这不是一个序列点。您不能依赖操作数的评估顺序。但是,可以保证对两个操作数进行评估。

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

于 2009-11-18T19:55:07.547 回答
23

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

那将是“优雅”的解决方案:)。对于下一个进入您项目的开发人员来说,依赖评估顺序的副作用远非优雅、容易出错且难以理解。当然,依赖副作用与以下代码片段形成对比,这是一个完全合乎逻辑且有效的用例,仅依赖于评估顺序:

if ( obj != NULL && obj->foo == blah ) { /* do stuff */ }
于 2009-11-18T19:54:38.167 回答
14

是的,有内置的运算符可以做到这一点。 +执行非短路 OR 并*执行 AND。

☺</h1>

#include <iostream>
using namespace std;

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

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

输出:

真的

错误的

于 2009-11-18T20:45:05.913 回答
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)); 

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

于 2009-11-18T20:03:10.637 回答
3

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

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

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

另一种可能性,但我倾向于反对,是让这两个函数返回一个重载“&&”运算符的类型。由于重载运算符调用一个函数,它总是计算两个操作数,即使在内置运算符没有的情况下(如 &&)——通常这是一个问题,但在这种情况下,这正是你想要的:

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可能会有所帮助,但我想不出一个能很好地反映意图而又不会变得如此冗长的名称,这将是一个净损失。

于 2009-11-18T20:34:45.690 回答
2

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

话虽如此,不要超载operator&&operator||. 善待您的维护程序员,他们会查看&&||假设他们确实发生了短路。

于 2009-11-18T20:28:09.473 回答
2

为此目的引入了一个近乎通用但通常未记录的非标准运算符x ?: y,由 GCC 与(x if non-zero else y) 一起开创,现在可悲的是删除了>?最小<?/最大运算符及其复合赋值形式(参见http ://gcc.gnu.org/onlinedocs/gcc/Deprecated-Features.html)。可悲的是,他们似乎已经在使用&并且&&已经在使用,他们似乎一直在寻找合适的字符序列,但这只是我的意见 - 欢迎任何历史解释来解释为什么会选择它。

因此,虽然它目前不像许多其他运算符那样广为人知>!大多数 C 和 C++ 编译器(包括GCC 甚至 MSVC++) 来满足这个要求:

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

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

一定要试一试;-)。

于 2011-04-07T08:08:31.703 回答