【问题标题】:How does the unary minus operator work on booleans in C++?一元减号运算符如何处理 C++ 中的布尔值?
【发布时间】:2012-07-18 14:43:42
【问题描述】:

我目前正在将一些 OpenCV 代码从 C++ 转换为 Java。我不能使用 JavaCV,因为我们需要在本机 Java 中进行转换,而不是 JNA。在代码中的某一时刻,我得到了以下任务:

dst[x] = (uchar)(-(kHit >= kForeground));

其中dstuchar*kHitkForegroundints。

我一直找不到任何关于它是如何工作的,Java 不会将它识别为一个操作。在代码的另一点对这两个变量进行了操作,它存储了两个值之一:255 或 0。

有问题的代码来自opencv/video/src/bgfg_gaussmix.cpp

【问题讨论】:

    标签: c++ unary-operator


    【解决方案1】:

    在 C++ 中,布尔表达式产生两个值之一 - 01。当您将一元减号- 应用于结果时,您将得到0-1。当您将-1 重新解释为uchar 时,您将得到255

    您可以使用条件将此表达式转换为 Java:

    dst[x] = (kHit >= kForeground) ? 255 : 0;
    

    由于分支,它不会像原来的那样快。但是,您对它的速度几乎无能为力,因为 Java 缺乏将布尔值重新解释为数字的能力。

    【讨论】:

    • 这是有道理的,而且我可以很容易地自己测试和发现。感谢您如此简洁地指出。
    • 从技术上讲,布尔表达式产生truefalse,当提升为int 时,将获得10 的值。
    【解决方案2】:

    kHit >= kForeground 返回truefalse,这在C++ 中的意思是10。前面的减号将其转换为-10。对uchar ((uchar)) 的强制转换为0 返回0,并为否定-1 换行到255

    根据 Konrad 的评论,我也怀疑这是否定义良好。 它定义良好,但就可读性而言,它仍然是一段糟糕的代码。 :)

    【讨论】:

    • 一些编译器/机器上。此代码不必要地不可移植。
    • C++ 标准是否没有明确指定无符号类型的行为就像二进制补码一样,所以这应该很好定义(因为 true==1 和 false==0 也很好定义)?
    • @KonradRudolph:标准指定A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one. [conv.prom] 和If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type) [conv.integral]。所以我认为这段代码实际上是定义良好的,并且可以跨兼容的编译器移植。
    • @ChristianRau: bool 既没有签名也没有未签名,但这并不重要,因为它将被提升为int 一元 - 被应用之前。关于答案中的最后一段,定义明确。该标准保证了这一点。除了 Luc 的引用,标准规定积分提升适用于一元 - 的评估。
    • @DavidRodríguez-dribeas 这就是我的意思。从boolint 的转换定义明确,从负数到无符号的转换也是如此。
    【解决方案3】:

    它的基本作用如下:

    kHit >= kForeground
    

    是布尔类型的表达式

    -(kHit >= kForeground)
    

    将此 bool 转换为 int(基于 true==1false==0)并将其取反,从而得到 true==-1false==0

    然后将其转换为uchar,从而产生-1==2550==0

    需要注意的是,虽然看起来使用了数字的底层实现细节,但所有这些转换都受到 C++ 和 C 标准的保证,因为负无符号数被指定为根据二进制补码运行。

    但如果 Java 不支持这一点,你总是可以用条件赋值来替换它:

    dst[x] = (kHit>=kForeground) ? 255 : 0;
    

    【讨论】:

      【解决方案4】:

      表达式(kHit >= kForeground) 产生一个布尔值,其值为truefalse。当应用一元 - 时,bool 被提升为 int,并且转换为 true 生成 1 或为 false 生成 0。推广后,标志改为-10,再由外联转为uchar

      请注意,重要的信息是一元 operator- 不应用于布尔值,而是将布尔值转换为 int 然后应用它。这可以用一些模板魔法来测试:

      template <typename T, typename U>
      struct same_type {
          static const bool value = false;
      };
      template <typename T>
      struct same_type<T,T> {
          static const bool value = true;
      };
      template <typename T>
      void f( T value ) {
          std::cout << "Is int? " << std::boolalpha << same_type<T, int>::value << "\n";
          std::cout << "Is bool? " << same_type<T, bool>::value << "\n";
      }
      int main() {
          f(-true);
      }
      

      f 模板使用上面的same_type 模板(简单到可以理解),针对intbool 测试传递参数的类型。如果我们以-true 作为参数调用f 模板,类型推导将设置T 为表达式-true 的类型。如果你运行程序,你会看到它打印出Is int? true\nIs bool? false

      【讨论】:

      • 很好的答案,但我认为您可以通过两个基本重载使积分转换的说明更加清晰。 void f(int) { cout &lt;&lt; "int\n"; } void f(bool) { cout &lt;&lt; "bool\n"; } f(true); f(-true);
      • @LucTouraille:我想,我的工具箱里只有那个hammer(现在我想到了一个更简单的方法:template &lt;typename T&gt; void print_type(T); print_type(-true);print_type 已声明,未定义)将告诉你链接器消息中的类型
      猜你喜欢
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-19
      • 2019-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多