【问题标题】:Lazy, overloaded C++ && operator?懒惰、重载的 C++ && 运算符?
【发布时间】:2013-04-08 13:10:49
【问题描述】:

我正在尝试实现我自己的布尔类,但无法为 && 复制本机语义。下面的人为代码演示了这个问题:



    #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;
}

编译运行后,结果为:

本国的 && 第一的 重载 && 第二 第一的

换句话说,布尔值上的 && 是惰性的(正如任何 C++ 程序员所期望的那样),但重载的 && 不是(至少这个 C++ 程序员没有预料到)。

有没有办法让重载的 && 变得懒惰?我可以找到各种完整的惰性求值方案来提供类似 Haskell 的功能,但对于我的用例来说,它们似乎完全是矫枉过正。

【问题讨论】:

  • 懒惰是指短路。重载的运算符没有短路。
  • 这个问题正是不建议重载&amp;&amp;操作符的原因。
  • 请注意,重载运算符不能短路的原因是MyBool aBool作为参数传递给它。所以MyBool(f2()) 需要在operator&amp;&amp; 的实现有机会运行之前计算。理论上,您可以编写一个模板operator&amp;&amp; 重载,其RHS 是一个返回MyBool 的函子。然后仅当 LHS 评估为真时才调用该函子。然后在 C++11 中,调用者可以编写一个 lambda:MyBool(f1()) &amp;&amp; []() { return MyBool(f2()); }。但在实践中,不要这样做——当你必须在每次调用时明确指定惰性求值时,它是相当丑陋的。

标签: c++ boolean operator-keyword lazy-evaluation


【解决方案1】:

您不应该超载bool operator&amp;&amp;,因为您会丢失短路评估,正如您所发现的那样。

正确的方法是给你的类一个 bool 转换运算符

class MyBool {
 public:
  bool theValue;
  MyBool() {}
  MyBool(bool aBool) : theValue(aBool) {}
  explicit operator bool() { return theValue; }
};

请注意,显式转换运算符需要符合 C++11。如果您没有这个,请查看safe bool idiom

【讨论】:

  • +1,但需要注意的是explicit operators是C++11的特性,C++03需要Safe Bool成语。
【解决方案2】:

有没有办法让重载的 && 变得懒惰?

没有。

【讨论】:

    【解决方案3】:

    您几乎可以使用the expression template idiom 懒惰地评估任何东西,包括但不限于内置版本短路的运算符。但这比您在这种情况下需要做的工作更多,因为那时您的 MyBool 类将需要 很多 更多代码。

    【讨论】:

    • “你可以让几乎任何东西都懒惰地评估”——这是一种误导,因为这种方法只适用于协作的用户定义类型。例如,对于任何 T* p;myBool &amp;&amp; ++p,您不能将增量短路。
    【解决方案4】:

    如果你真的想要短路并且愿意牺牲运算符语法,你可以将你的operator&amp;&amp; 方法重命名为_and,定义一个AND() 宏,并写AND(x,y) 而不是x&amp;&amp;y

    #define AND(x,y) (x._and(x.theValue ? y : MyBool(false)))
    

    使用一些macro hacks,您可以让AND() 接受可变数量的参数。

    此处的_and() 方法不打算在此处“公开”使用,但必须声明为公开,因为您不能friend 宏。

    对于像 MyBool 类这样简单的东西,这可能是不必要的。但是,如果您需要您的 operator&amp;&amp; 具有特殊的副作用,例如更新 this 上的某些状态,那么这可以完成工作。

    【讨论】:

      猜你喜欢
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      • 1970-01-01
      相关资源
      最近更新 更多