重载 && 和 || 实际上是否有原因?不短路吗?

2024-02-22

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

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


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

我不知道该设计过程如何最终落入这个不幸的地方的细节。然而,了解后来的设计过程如何考虑到这一令人不快的结果是相关的。在C#中,重载&&操作员is短路。 C# 的设计者是如何实现这一点的呢?

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

A && B

在道德上可以被实现为等同于:

operator_&& ( A, ()=> B )

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

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

相反,C# 解决方案将问题分解为两个独立的问题:

  • 我们应该评估右边的操作数吗?
  • 如果上面的答案是“是”,那么我们如何组合两个操作数?

因此,通过将超载定为非法来解决问题&&直接地。相反,在 C# 中你必须重载two运算符,每个运算符都回答这两个问题之一。

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# 要求 if 运算符false然后提供操作员true还必须提供,它回答了这个问题:这件事是“真实的吗?”。通常没有理由只提供一个这样的运算符,因此 C# 需要两者都提供。)

考虑以下形式的语句:

C cresult = cleft && cright;

编译器会为此生成代码,就像您编写了这个伪 C# 一样:

C cresult;
C tempLeft = cleft;
cresult = C.false(tempLeft) ? tempLeft : C.&(tempLeft, cright);

正如您所看到的,总是评估左侧。如果确定它是“假的”,那么这就是结果。否则,计算右侧,并且eager用户定义的运算符&被调用。

The ||运算符以类似的方式定义,作为运算符 true 和 eager 的调用|操作员:

cresult = C.true(tempLeft) ? tempLeft : C.|(tempLeft , cright);

通过定义所有四个运算符——true, false, & and |-- C#让你不仅可以说cleft && cright而且还没有短路cleft & cright,并且if (cleft) if (cright) ..., and c ? consequence : alternative and while(c), 等等。

现在,我说所有的设计过程都是妥协的结果。这里 C# 语言设计者设法短路了&& and ||是的,但是这样做需要重载four运算符而不是two,有些人觉得很困惑。运算符 true/false 功能是 C# 中最难理解的功能之一。拥有一种 C++ 用户熟悉的明智且简单的语言的目标遭到了短路的愿望以及不实现 lambda 提升或其他形式的惰性求值的愿望的反对。我认为这是一个合理的妥协立场,但重要的是要认识到它is一种妥协的立场。只是一个不同的比 C++ 设计者所采取的妥协立场。

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

重载 && 和 || 实际上是否有原因?不短路吗? 的相关文章

  • 简单的C问题

    作为我正在进行的项目的一部分 我必须开始学习 C 我已经开始解决其中的 欧拉 问题 并且遇到了麻烦 我必须找到 1000 以下的所有 3 或 5 的倍数之和 有人可以帮助我吗 谢谢 include
  • 在 C++ 中,当我将值传递给函数时,它是否总是转换为适当的类型?

    如果我有一个像这样的函数void func size t x 我称该函数为func 5 5 立即转换为size t类型 这通常适用于所有类型吗 我问这个问题是因为我发誓我见过人们编写代码 他们做类似的事情func 5 0 将 5 作为双精度
  • 在 C++ 中,std::string::push_back() 的摊余复杂度是 O(1) 吗?

    我知道标准指定它适用于向量 但是字符串呢 是的 它是摊销常数时间 请参见第 716 页的表 101本文件的 http www open std org jtc1 sc22 wg21 docs papers 2012 n3485 pdf 表
  • 有没有办法让我的程序用更少的代码运行?

    我为学校作业编写了以下代码 它编译并打印所有正确的消息 但出于我自己的好奇心 我想知道我的代码是否可以缩短并且仍然有效 我尝试了 signal 而不是 sigaction 但我听说 sigaction 比 signal 更受青睐 此外 此任
  • 通过 EUSART PIC18F45K80 打印消息

    我正在尝试向 Docklight 发送串行消息 但始终收到空值 我正在使用带有 XC8 MPLAB X 的 PIC18F45K80 我的代码中的所有内容似乎都是正确的 但我想我错了 我该如何修复它 include
  • 我可以将特定警告视为错误吗?

    以下是我有时在学生代码中看到的模式的简化版本 bool foobar int a int b if a lt b return true 当然 真正的代码要复杂得多 Visual Studio 报告警告 C4715 并非所有控制路径都会返回
  • C++ Linux GCC 应用程序中的 GUID

    我有很多服务器运行这个 Linux 应用程序 我希望他们能够生成一个碰撞概率较低的 GUID 我确信我可以从 dev urandom 中提取 128 个字节 这可能没问题 但是有没有一种简单易用的方法来生成与 Win32 更等效的 GUID
  • memccpy 返回比 src 起始地址更低的内存地址

    我有一个学校项目 我必须重新编码memccpy 功能 我使用 2 个程序来检查我的代码是否正常工作 第一个是只有一个主程序的小程序 第二个程序是另一个学生开发的 可以找到here https github com yyang42 mouli
  • 在 C++ 中初始化指针

    可以在声明时将指针分配给值吗 像这样的东西 int p 1000 是的 您可以在声明时初始化指向值的指针 但是您不能这样做 int p 1000 是个地址运算符 并且您不能将其应用于常量 尽管如果可以 那会很有趣 尝试使用另一个变量 int
  • Docker 不遵循构建目录中的符号链接

    我正在对一个应用程序进行 Docker 化 其中涉及通过 Clang 将二进制文件与其他 C 文件链接 我们维护二进制文件的符号链接版本 因为它们在整个代码库中使用 我的 Docker 构建目录包含整个代码库 包括源文件以及这些源文件的符号
  • 如何在Phone类库项目中添加ResourceDictionary并访问它

    我正在开发一个项目 其中我有一个引用图书馆项目的子项目 在我的库项目 电话类库 中 如何创建 ResourceDictionary xaml 其中我需要添加一些样式并在 xaml 文件和 cs 文件中使用它 我需要访问 xaml 文件中的
  • 为什么 C++20 范围不只提供管道语法?

    我知道这个问题听起来很奇怪 所以这里有一些背景信息 最近 我很失望地了解到 C 20 范围内的映射缩减并不像人们所期望的那样工作 即 const double val data transform accumulate 不起作用 你必须这样
  • 验证域用户凭据

    我需要一种方法来验证 Windows 上本机 C 的用户 密码对 输入的是用户名和密码 用户可以是 DOMAIN user 格式 基本上我需要编写一个函数 如果用户 密码是有效的本地帐户 则返回 true 第1部分 如果用户 密码在给定的域
  • C# 或 Windows 相当于 OS X 的 Core Data?

    我迟到了 现在才开始在 OS X Cocoa 中使用 Core Data 它令人难以置信 并且确实改变了我看待事物的方式 C 或现代 Windows 框架中是否有等效的技术 即拥有可免费保存 数据管理 删除 搜索的托管数据类型 还想知道Li
  • 如何明智地解释这个编译器警告?

    当我执行这段代码时question https stackoverflow com a 51056490 2411320 我收到这个警告 warning format d expects argument of type int but a
  • PARITY_NONE 是 C++ Windows 中的关键字吗?

    我正在使用 boost 编写一个串行库 并且我有一个枚举 enum parity t PARITY NONE PARITY ODD PARITY EVEN 我收到如下错误 错误 1 错误 C2059 语法错误 我无法弄清楚问题是什么 然后我
  • 为什么 char 数组需要 strcpy 而 char star 不需要 - 在 C 中使用结构

    我对这段代码有一个误解 typedef struct EXP int x char name char lastName 40 XMP main XMP a a name eaaa a lastName strcpy a lastName
  • 如何正确地将十六进制转义添加到字符串文字中?

    当你有C语言的字符串时 你可以在里面直接添加十六进制代码 char str abcde a b c d e 0x00 char str2 abc x12 x34 a b c 0x12 0x34 0x00 这两个示例在内存中都有 6 个字节
  • 使texture2D在运行时/脚本Unity3D中可读[重复]

    这个问题在这里已经有答案了 我有一个插件 可以让我访问 Android 手机图库中的图片 这给了我一个Texture2D类型的纹理 然后我想使用 GetPixels 函数对其进行编辑 但默认情况下它未设置为可读 如何使纹理可读 以便我可以在
  • ASP.NET API:尚未为此 DbContext 配置数据库提供程序

    我正在尝试从我的 Net Core API 项目连接到 MySql 数据库 这是我的上下文类 public class MyContext DbContext public MyContext public MyContext DbCont

随机推荐