How does the unary minus operator work on booleans in C++?

断了今生、忘了曾经 提交于 2019-12-01 18:12:51

In C++ a boolean expression produces one of two values - 0 or 1. When you apply the unary minus - to the result, you get 0 or -1. When you re-interpret -1 as uchar, you get 255.

You can convert this expression to Java with a conditional:

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

Because of branching, it is not going to be as fast as the original one. There's little you can do about the speed of it, however, as Java lacks abilities to re-interpret boolean values as numerics.

kHit >= kForeground returns either true or false, which in C++ sort of means 1 or 0. The minus in front transforms this to -1 or 0. The cast to uchar ((uchar)) returns 0 for 0 and wraps to 255 for the negative -1.

Following Konrad's comment, I'm also skeptical this is well defined. It is well defined, but it's still an awful piece of code in terms of readability. :)

What it basically does is following:

kHit >= kForeground

is an expression of type bool

-(kHit >= kForeground)

converts this bool into an int (based on true==1 and false==0) and negates it, which results in true==-1 and false==0.

This is then converted into a uchar, which results in -1==255 and 0==0.

It has to be noted that though seeming as using the underlying implementation details of the numbers, all those conversions are guaranteed by the C++ and C standards, as negative unsigned numbers are specified to behave according to twos-complement.

But if Java doesn't support this, you can always replace it by a conditional assignment:

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

The expression (kHit >= kForeground) yields a boolean that has value true or false. When the unary - is applied, the bool gets promoted to an int, and the conversion yields 1 for true or 0 for false. After the promotion, the sign is changed into -1 or 0 and then it is converted to uchar by the outer cast.

Note that the important bit of information is that the unary operator- is not applied to a boolean, but the boolean is converted to int and it is then applied. That can be tested with a bit of template magic:

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);
}

The f template tests the type of the passed argument against int and bool by using the same_type templates above (trivial enough to understand). If we call the f template with -true as argument type deduction will set T to be the type of the expression -true. If you run the program, you will see that it prints Is int? true\nIs bool? false.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!