【问题标题】:Is !! a safe way to convert to bool in C++?是 !!在 C++ 中转换为 bool 的安全方法?
【发布时间】:2010-09-17 09:25:48
【问题描述】:

[此问题与this one相关但不相同。]

如果我尝试使用某些类型的值作为布尔表达式,我会收到警告。我有时不会取消警告,而是使用三元运算符 (?:) 转换为布尔值。使用两个非运算符 (!!) 似乎做同样的事情。

这就是我的意思:

typedef long T;       // similar warning with void * or double
T t = 0;
bool b = t;           // performance warning: forcing 'long' value to 'bool'
b = t ? true : false; // ok
b = !!t;              // any different?

那么,双重非技术真的做同样的事情吗?它比三元技术更安全还是更安全?这种技术对于非整数类型是否同样安全(例如,void *double 用于 T)?

我不是在问!!t 是否是好风格。我在问它在语义上是否与 t ? true : false 不同。

【问题讨论】:

  • 当我看到像 "b = t ? true : false;" 这样的行时我总是很想用“b = t”行替换它。已经有一个隐式转换为 bool,为什么要切分语义?
  • 正如 Q 所说,因为 b=t 会发出警告
  • 有趣的是有多少人在主观上反对!!。双重否定是 JavaScript 中 惯用的 cast-to-bool 工具,如果 javascripters 得到它,我希望 C++ 用户也会这样做。
  • 双重否定在大多数脚本语言中很常见stackoverflow.com/questions/524658/what-does-mean-in-ruby 因此,严格禁止在高级、可理解的代码中使用(至少由作者本人).. :)
  • @GregD 一种情况是为结构中的位字段标志赋值。您的解决方案会截断(至少在某些编译器中),而此处提供的其余解决方案会将标志设置为相关的真值。假设编译器会(为您)做正确的事情并不是明智之举。并且将位字段类型设置为布尔值并不会改变这一点(至少对于我正在处理的编译器)。未定义的行为。

标签: c++ visual-c++ boolean


【解决方案1】:

的论点!运算符和三元运算符的第一个参数都隐式转换为布尔值,所以 !!和?:是 IMO 愚蠢的演员阵容多余的装饰。我投票给

b = (t != 0);

没有隐式转换。

【讨论】:

    【解决方案2】:

    或者,您可以这样做:bool b = (t != 0)

    【讨论】:

    • 我总是使用这个,因为我认为它最清楚地表达了意图。在生成警告的情况下,这实际上是编译器正在执行的操作,但对此是明确的。这 !!对我来说似乎很老套。
    • 如果 t 是其类提供运算符 (bool) 的对象,则不起作用,而其他建议则可以。
    【解决方案3】:

    小心!

    • 布尔值是关于真假。
    • 整数大约是整数。

    这些是非常不同的概念:

    • 真假是关于决定事物的。
    • 数字是关于计数的。

    在桥接这些概念时,应该明确地完成。我最喜欢 Dima 的版本:

    b = (t != 0);

    该代码清楚地表明:比较两个数字并将真值存储在布尔值中。

    【讨论】:

      【解决方案4】:

      所有有效的技术,都将生成相同的代码。

      就我个人而言,我只是禁用警告,以便使用最简洁的语法。转换为 bool 并不是我担心会意外做的事情。

      【讨论】:

      • 是的,感谢 Microsoft 为我们提供清晰和惯用的 C 代码的警告。
      • 我确实想知道是什么让他们添加了警告;一定有人在做某事真的愚蠢...
      • 也许它对某些目标架构有影响?除了正常转换和转换的警告之外,MS 没有说是“设计使然”
      • @MikeF 警告在那里,所以编译器可以“警告”你一些你可能不打算做的事情。禁用警告可能是“干净的”,但可能会导致拼写错误或意外错误。 (比如将 long 传递给需要 bool 的函数?)
      • 我最近看到一段代码,打算比较两个指针,但实际上指针被隐式地转换为bool,所以你可能会猜它没有很好地工作。我反对全面禁用警告,除非涉及编译器错误(就像某些 VC++ 6.0 警告的情况一样)
      【解决方案5】:


      是的,它是安全的。


      0 被解释为假,其他一切都为真,
      因此 !5 是错误的
      !0 是真的
      所以 !!5 是真的

      【讨论】:

        【解决方案6】:

        我不会使用:

        bool b = !!t;
        

        这是最不可读的方式(因此最难维护)

        其他的视情况而定。
        如果您要转换为仅在布尔表达式中使用。

        bool b = t ? true : false;
        if (b)
        {
            doSomething();
        }
        

        那么我会让语言为你做这件事:

        if (t)
        {
            doSomething();
        }
        

        如果您实际存储的是布尔值。那么首先我想知道为什么你首先需要演员阵容。假设您需要 long 和 bool 值,我会根据情况考虑以下所有内容。

        bool  b = t ? true : false;      // Short and too the point.
                                         // But not everybody groks this especially beginners.
        bool  b = (t != 0);              // Gives the exact meaning of what you want to do.
        bool  b = static_cast<bool>(t);  // Implies that t has no semantic meaning
                                         // except as a bool in this context.
        

        总结: 使用对您所处的环境最有意义的内容。
        试着让你在做什么变得显而易见

        【讨论】:

        • “让语言来做”(又名“通常的转换”)是产生警告的原因。可能需要这样做的示例: struct C { void * hdl;无效 * get_hdl() { 返回 hdl; } bool has_hdl() const { 返回 hdl ?真假; }
        • 可读性在旁观者的眼中。例如,我认为前缀操作符比后缀操作符更易读,简洁胜过冗长,枯燥胜过重复。 (double) negation 是前缀运算符 (win),比三元运算符 (win) 短,可以被视为单个运算符,而三元运算符带有三个不同的表达式(加上运算符语法)。
        【解决方案7】:

        我建议永远不要抑制该警告,也不要使用 c cast (bool) 来抑制它。转换可能并不总是像您想象的那样被调用。

        计算结果为 true 的表达式和该值的布尔值之间存在差异。

        两个!!和 ternary 习惯了,但如果您不想使用重载类型转换为 bool 来定义内部类型,它们会以类似方式完成工作。

        Dima 的方法也很好,因为它将表达式的值分配给布尔值。

        【讨论】:

        • 想出一个例子,该警告会对您有任何帮助吗?
        • 好吧,您可能会丢失该演员表中的信息。也许您正在从一个在此转换中不会丢失任何信息的环境中移植代码。在这种情况下,您是否想知道任何丢失的位。
        • 您当然会丢失信息。这就是转换为 bool 的全部意义!
        • @wilhelmtell:什么样的环境不会丢失int->bool中的信息?
        • @Mike:随着代码的变化,您转换为 bool 的值可能是 typedef 的,因此生成的代码可能会发生变化。此外,有些编译器默认使用有符号和无符号字符,这可能会产生不同的结果。
        【解决方案8】:

        如果担心警告,也可以强制转换:bool b = (bool)t;

        【讨论】:

        • 其实完全等价于 bool b = t;并生成相同的警告
        • 不要使用 C 类型转换。 C++ 强制转换是有原因的。另外,我没有在我的编译器上尝试这个,但我不希望它产生任何警告,因为你明确要求编译器做一些事情。编译器通常只会在隐含的事情发生时警告你。
        • 这样做时,我从来没有在我的 Ubuntu 机器上看到 GCC 下的警告
        • @wilhelmtell:试一试;你会发现 VC++ 确实 实际上会警告你关于 '(bool)a'、'bool(a)' 和 'static_cast(a)'。
        • @warren:啊,发帖人没有提到这是 VC++ 特定的,标签相应地进行了编辑。
        【解决方案9】:

        我真的很讨厌!!t!!!!!!。它带有 C 和 C++ 最糟糕的东西的味道,即对你的语法过于聪明的诱惑。

        布尔 b(t != 0); // 恕我直言,这是最好的方法,它明确显示正在发生的事情。

        【讨论】:

          【解决方案10】:

          与 0 的比较效果不太好。 这又回来了-为什么!与三元?

          class foo { public: explicit operator bool () ; };
          
          foo f;
          
          auto a = f != 0; // invalid operands to binary expression ('foo' and 'int')
          auto b = f ? true : false; // ok
          auto c = !!f; // ok
          

          【讨论】:

          • 这个答案有什么与众不同的新信息吗?如果您决定回答一个具有完善且正确答案的旧问题,那么在当天晚些时候添加新答案可能不会让您获得任何荣誉。如果您有一些独特的新信息,或者您确信其他答案都是错误的,请务必添加一个新答案,但是在提出问题很长时间后提供相同基本信息的“另一个答案”通常不会不会为你赢得太多荣誉。
          • 是的。没有其他人发现 != 0 经常会失败。
          【解决方案11】:

          !!可能很紧凑,但我认为它不必要地复杂。在我看来,最好禁用警告或使用三元运算符。

          【讨论】:

            【解决方案12】:

            我会使用 b = (0 != t) - 至少任何理智的人都可以轻松阅读它。如果我在代码中看到双重问题,我会非常惊讶。

            【讨论】:

              【解决方案13】:

              禁用警告。

              先写清楚;然后简介;然后根据需要优化速度。

              【讨论】:

                【解决方案14】:

                !!仅当您以算术方式使用布尔表达式时才有用,例如:

                c = 3 + !!extra; //3 or 4
                

                (谁的风格是不同的讨论。)当你只需要一个布尔表达式时,!!是多余的。写作

                bool b = !!extra;
                

                与以下内容一样有意义:

                if (!!extra) { ... }
                

                【讨论】:

                  【解决方案15】:

                  我推荐使用

                  如果 (x != 0)

                  如果 (x != NULL)

                  而不是 if(x);它更易于理解和可读。

                  【讨论】:

                  • 对我来说if(x) 更具可读性。它以最简洁的方式表示if not zero
                  【解决方案16】:

                  替身对我来说并不好笑,在调试代码中与在优化代码中会大不相同。

                  如果你爱上了!!你总是可以宏它。

                  #define LONGTOBOOL(x) (!!(x))
                  

                  (顺便说一句,在这些情况下我更喜欢三元运算符)

                  【讨论】:

                    【解决方案17】:

                    我会使用 bool b = t 并留下编译警告,评论这一特定行的安全性。禁用警告可能会在代码的另一部分中咬你。

                    【讨论】:

                    • 留下需要忽略的警告会适得其反;它会导致您错过其他更重要的警告。零警告政策是最好的。
                    • 是的,但禁用警告更糟糕,它会关闭可能更重要的警告。正如 Edgar 上面所说,布尔值是关于真值的,整数是关于数字的。应该以某种方式保留这种区别。
                    猜你喜欢
                    • 2010-12-30
                    • 2010-12-22
                    • 2015-12-19
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-01-14
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多