c++ - 重载 && 和 || 是否真的有原因?不要短路?

标签 c++ c++11 operator-overloading logical-operators short-circuiting

运营商的短路行为&&||对于程序员来说是一个了不起的工具。

但是为什么它们在过载时会失去这种行为呢?我知道运算符只是函数的语法糖,而是 bool 的运算符。有这种行为,为什么要仅限于这种单一类型?这背后有什么技术原因吗?

最佳答案

所有的设计过程都会导致相互不兼容的目标之间的妥协。可惜设计过程为重载&& C++ 中的运算符产生了一个令人困惑的最终结果:正是您想要的特性 && -- 它的短路行为 -- 被省略了。

设计过程如何在这个不幸的地方结束的细节,我不知道。然而,看看后来的设计过程如何考虑这种令人不快的结果是很重要的。在 C# 中,重载 &&运算符(operator)短路。 C# 的设计者是如何做到这一点的?

其他答案之一建议“lambda 提升”。即:

A && B

可以实现为在道德上等同于:
operator_&& ( A, ()=> B )

其中第二个参数使用某种惰性求值机制,以便在求值时产生表达式的副作用和值。重载运算符的实现只会在必要时进行惰性求值。

这不是 C# 设计团队所做的。 (旁白:虽然 lambda 提升是我在做 ?? 运算符的表达式树表示时所做的,这需要延迟执行某些转换操作。然而,详细描述这将是一个主要的题外话。我只想说:lambda 提升有效,但重量足够大,我们希望避免它。)

相反,C# 解决方案将问题分解为两个单独的问题:
  • 我们应该评估右手操作数吗?
  • 如果上面的答案是"is",那么我们如何组合两个操作数?

  • 因此,通过使重载 && 成为非法来解决问题。直接。相反,在 C# 中,您必须重载两个运算符,每个运算符都回答这两个问题之一。
    class C
    {
        // Is this thing "false-ish"? If yes, we can skip computing the right
        // hand size of an &&
        public static bool operator false (C c) { whatever }
    
        // If we didn't skip the RHS, how do we combine them?
        public static C operator & (C left, C right) { whatever }
        ...
    

    (旁白:实际上,三个。C# 要求,如果提供了运算符 false,则还必须提供运算符 true,这回答了这个问题:这个东西是“真实的吗?”。通常没有理由提供只有一个这样的运算符,所以 C# 需要两者。)

    考虑以下形式的声明:
    C cresult = cleft && cright;
    

    编译器为此生成代码,因为您认为您编写了这个伪 C#:
    C cresult;
    C tempLeft = cleft;
    cresult = C.false(tempLeft) ? tempLeft : C.&(tempLeft, cright);
    

    如您所见,始终评估左侧。如果它被确定为“false-ish”,那么它就是结果。否则,评估右侧,并使用急切的用户定义运算符 &被调用。
    ||运算符以类似的方式定义,作为对运算符 true 和急切 | 的调用。运营商:
    cresult = C.true(tempLeft) ? tempLeft : C.|(tempLeft , cright);
    

    通过定义所有四个运算符 -- true , false , &| -- C#让你不仅可以说cleft && cright但也非短路cleft & cright ,还有 if (cleft) if (cright) ... , 和 c ? consequence : alternativewhile(c) ,等等。

    现在,我说所有的设计过程都是妥协的结果。在这里,C# 语言设计者设法实现了短路 &&||是的,但这样做需要重载四个运算符而不是两个,有些人会觉得这令人困惑。运算符 true/false 功能是 C# 中最不为人所知的功能之一。拥有一种为 C++ 用户所熟悉的明智而直接的语言的目标与短路的愿望和不实现 lambda 提升或其他形式的惰性求值的愿望相反。我认为这是一个合理的妥协立场,但重要的是要意识到这是一个妥协立场。只是与 C++ 设计者所采取的妥协立场不同。

    如果您对此类运算符的语言设计主题感兴趣,请考虑阅读我关于为什么 C# 不在可空 bool 值上定义这些运算符的系列:

    http://ericlippert.com/2012/03/26/null-is-not-false-part-one/

    关于c++ - 重载 && 和 || 是否真的有原因?不要短路?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25913237/

    相关文章:

    c++ - 在 Linux Mint 上使用多个版本的 libboost

    c++ - 使用 cmake 在调试构建期间为单个项目指定发布

    c++ - 右值模板参数隐式用作左值,并且 std::forwarding 工作

    c++ - 没有 typedef 的运算符 member_function_pointer_type()?

    c++ - 重载运算符 : const vs non-const return type : any difference of performance?

    c++ - 为什么 any_cast 函数重载不会导致歧义?

    c++ - 如何检查USB插槽中是否存在空的闪存卡读卡器?

    c++ - 初始化列表: cannot convert ‘Participant’ to ‘unsigned int’ in initialization

    c++ - 有没有办法将一对元组剥离为可变参数模板类型或使用可变参数类型实例化某些内容?

    c++ - 覆盖原始数据类型的转换