我正在尝试实现我自己的布尔类,但无法复制 && 的本机语义。以下人为的代码演示了该问题:
#include <iostream>
class MyBool {
public:
bool theValue;
MyBool() {}
MyBool(bool aBool) {theValue = aBool;}
MyBool operator&& (MyBool aBool) {return theValue && aBool.theValue;}
};
bool f1() {std::cout << " First\n"; return false;}
bool f2() {std::cout << " Second\n"; return false;}
int main(int argc, char** argv) {
std::cout << "Native &&\n";
f1() && f2();
std::cout << "Overloaded &&\n";
MyBool(f1()) && MyBool(f2());
return 0;
}
编译运行后结果为:
Native &&
First
Overloaded &&
Second
First
换句话说,bool 上的 && 是惰性的(正如任何 C++ 程序员所期望的那样),但重载的 && 却不是(正如这个 C++ 程序员至少没有期望的那样)。
有没有办法让重载&&变得懒惰?我可以找到各种全面的惰性评估方案来提供类似 Haskell 的功能,但它们对于我的用例来说似乎完全是多余的。
您不应该过载
bool operator&&
,因为正如您所发现的,您会失去短路评估。
正确的方法是为你的类提供一个 bool 转换运算符
class MyBool {
public:
bool theValue;
MyBool() {}
MyBool(bool aBool) : theValue(aBool) {}
explicit operator bool() { return theValue; }
};
请注意,显式转换运算符需要符合 C++11。如果您没有这个,请查看safe bool idiom。
有没有办法让重载&&变得懒惰?
没有。
您可以使用表达式模板惯用语使几乎任何东西进行延迟计算,包括但不限于内置版本短路的运算符。但这比您在这种情况下需要的工作量要多,因为那时您的
MyBool
类将需要很多更多代码。
如果您确实想要短路并且愿意牺牲运算符语法,您可以将
operator&&
方法重命名为 _and
,定义 AND()
宏,并编写 AND(x,y)
而不是 x&&y
。
#define AND(x,y) (x._and(x.theValue ? y : MyBool(false)))
通过一些宏黑客,您可以让
AND()
接受可变数量的参数。
此处的
_and()
方法不打算在此处“公开”使用,但必须声明为公开,因为您不能 friend
宏。
对于像您的
MyBool
类这样简单的事情,这可能是不必要的。但是,如果您需要 operator&&
具有特殊的副作用,例如更新 this
上的某些状态,那么这就可以完成工作。