【问题标题】:double as true / false双倍为真/假
【发布时间】:2012-06-26 23:06:20
【问题描述】:

Bjarne 建议使用 if 中的条件作为范围限制。特别是这个例子。

if ( double d = fd()  ) {
   // d in scope here...
}

我很好奇如何从真/假的意义上解释声明。

  1. 这是一个声明
  2. 这是一个双重的。

编辑: 它在 6.3.2.1 C++ 编程语言中作为推荐。

Edit2:templatetypedefs 对指针的建议,特别是动态转换,可能会给 Bjarnes 建议提供洞察力。

SteveJessop 告诉我: - 条件不是表达式,它也可以是声明,使用的值是正在评估的值。

【问题讨论】:

  • this question 的答案也将回答您的问题。
  • 我刚刚阅读了您正在谈论的部分,并感觉讨论更多是关于将其用作范围限制(并获得紧凑代码的额外好处)并且没有与特定的数据类型有很大关系。我认为他本可以将double 替换为int,并且仍然能够传达他想要传达的信息。我就是这么读的。
  • @jedwards 是的,但是使用 double 是在乞求答案。 int 声明仍然是一个值得回答的异常情况。
  • @Captain Giraffe:声明不是表达式。 if 语句的语法是“if (condition) statement”,条件的语法是“expression”或“type-specifier-seq declarator = assignment-expression”。 double d = fd() 是后者。请参阅标准中的[stmt.select]
  • @Mike:不幸的是,编写类似代码的人发明了 C++ 而你没有,所以我认为你的偏好不会胜出。也就是说,Stroustrup 将代码 sn-ps 以斜体而不是像几乎其他所有人一样使用固定宽度。所以他并没有赢得所有人。

标签: c++ if-statement type-conversion scoping variable-declaration


【解决方案1】:

您看到的代码是在if 语句中声明变量的专用技术。您通常会看到这样的内容:

if (T* ptr = function()) {
    /* ptr is non-NULL, do something with it here */
} else {
    /* ptr is NULL, and moreover is out of scope and can't be used here. */
}

一个特别常见的情况是在这里使用dynamic_cast

if (Derived* dPtr = dynamic_cast<Derived*>(basePtr)) {
     /* basePtr really points at a Derived, so use dPtr as a pointer to it. */
} else {
     /* basePtr doesn't point at a Derived, but we can't use dPtr here anyway. */
}

在您的情况下发生的情况是您在 if 语句中声明了 double。 C++ 自动将任何非零值解释为true,并将任何零值解释为false。这段代码的意思是“声明d并设置它等于fd()。如果它不为零,则执行if语句。”

也就是说,这是一个非常糟糕的主意,因为doubles 会受到各种舍入错误的影响,在大多数情况下它们无法为 0。这段代码几乎肯定会执行if 语句的主体,除非function 表现得非常好。

希望这会有所帮助!

【讨论】:

  • @bames53 这几乎就像你读懂了我的想法。我仍然想对 bool b = double d = fd(); 的不一致发表评论。虽然,但这可能是另一个问题。
  • "而且超出范围,不能在此处使用" - 它是 else 子句中的 in 范围,但当然有指针和智能指针你不能用一个测试为假的变量做很多事情,所以你通常看不到它在那里使用。我想可以分配另一个值。如果您将它与具有安全 bool 习惯用法以指示“失败”的用户定义类型一起使用,那么也许在 else 子句中您将询问对象为什么它“失败”。跨度>
  • 感谢您指出按位双重比较的非常糟糕的想法。
【解决方案2】:

在 Stroustrup 给出的示例中,if 块中的代码将一个值除以 d

if (double d = prim(true)) {
    left /= d;
    break;
}

除以 0 是未定义的行为,因此 在这种情况下在除之前测试 d 与值 0.0 是有意义的。出于 Stroustrup 所述的原因,将定义置于条件中是一种方便的方法。

您的代码没有说明为什么值 0.0 会特别,因此不清楚为什么有人会将 d 的定义与该测试结合起来。仅当您定义的类型的“假”值需要特殊处理时,才使用 Stroustrup 模式。否则就这样做:

{
    double d = fd();
    // d in scope here...
}

【讨论】:

  • 我只是阅读了该部分并没有建立联系——我认为这是一个一次性的例子——很好。对break; 有任何见解吗?
  • @jedwards:超出显而易见的范围(它打破了一些周围的循环或开关,未在此代码片段中显示)我不知道。也许这个代码片段取自章节/书中其他地方使用的一些代码?就此而言,我也不知道prim 的作用是什么。
  • 哇,我有点希望这是一些像these gems 一样吸引我的技巧。谢谢!
【解决方案3】:

它既是声明也是双重的。这相当于

{
    double d = fd();
    if (d) {
    }
}

但是,这种模式值得用一些额外的小语法来简化,因为它相当有用且很常见。此外,一旦开始添加 else 子句,转换就不太明显了,因为 d 超出了它们的范围。

此外,正如其他人所指出的,它通常很有用,但与 0 相比,FP 类型在特定方面存在一些问题。

【讨论】:

  • 这是我满意的第一个答案。这种语法无处不在。
  • 我的问题也涉及 bool b = double d = 0.0;
  • 您确定d 超出了else 分支的范围吗?
  • 刚刚测试过,d 还在 else 分支的作用域内:ideone.com/V7r4h
【解决方案4】:

if 语句基于赋值表达式中分配给变量的值。如果 double 计算结果为 0.0 以外的任何值,它将在内部运行代码。

请注意,您不应该将双精度数与零进行比较,但根据我的经验,它通常有效。

基本上,您不应该这样做。

该主题的其他贡献者发现该表达式用于排除零情况以避免被零除。这绝对是聪明的,就我而言,这种情况使这种用法合法化(但请考虑此类代码可能导致的混乱)。

【讨论】:

  • Bjarne 告诉我这是一个成语。只是说。 6.3.2.1 C++ 编程语言。
  • 他可能指的是双重d在范围内if 块内部(并且仅在内部)。这不一定是显而易见的。我的观点是,通常没有充分的理由将 double 类型转换为 bool。为什么不使用int 类型的变量,我不知道。 (这是一个很常见的成语)
  • 为什么你不应该将双精度数与零进行比较?它工作得非常好并且具有明确定义的行为。浮点数学可能会令人惊讶,但它不是巫术,也不能很好地接受这种建议。
  • 进入(比较浮点值)不是一个好习惯。零可能是一种特殊情况,因为对于浮点类型的所有实现,0 与等效大小的整数类型的 0 位等价。但是,当您得到与给出的示例类似的内容时,尚不清楚fd() 是否会返回一个非常接近零(但实际上不是零)或零的值。如果此技术实际上用于排除零的情况(因此不会发生除以零),这是一件的事情。
  • 哎呀!切勿使用整数比较来测试浮点零。 0x80000000 是 32 位(负)零。我的观点是,在很多情况下,正确的代码会产生明确的浮点零(很明显,乘以零)。你可以用它来编写正确的代码而不必担心。将 FPU 逻辑视为可以随机化输出的伏都教只是一个坏主意。
猜你喜欢
  • 1970-01-01
  • 2018-07-01
  • 2010-09-23
  • 2014-09-07
  • 1970-01-01
  • 2019-01-30
  • 2014-02-28
  • 2015-03-30
  • 1970-01-01
相关资源
最近更新 更多