operator++(bool)
Peter Hull

Did you know this was valid C++

#include <iostream>
using std::cout;
using std::endl;

int main ()
{
  bool b = false;
  cout << b << endl;
  b++;
  cout << b << endl;
  b++;
  cout << b << endl;
  return 0;
}

You can call increment on false to get true, and increment on true to get ... true.
And if you replace ++ with -- , that's not valid C++.

I only found this out just today; it's been slated to be deprecated in C++17 (link) Enjoy while you can!

Chris Katko

WHAT? I thought for sure (bool)++ was negate. This is like Javascript-level stupidity.

video

Is that compiler dependent?

[edit] Also, side note: Lots of people I know are surprised that you can multiply strings in some (read: good) languages. It just means repeat. Which is insanely useful when you need to do something like:

print "text header\n" + "-"*80 + "\n"

As well as other formatting I can't recall off the top my head. I love learning about stuff like that where you go "Where has this been all my life?"

torhu

Is b++ just the same as b = true? Anyone tested it or looked at the assembly?

By the way, negation would be b ^= 1. Unless C++ disallows it, of course :P

Chris Katko
#SelectExpand
1#include <stdio.h> 2int main() 3{ 4 bool a = false; 5 bool b = true; 6 printf("a = %i\n", a); 7 printf("b = %i\n", b); 8 9 printf("a++ = %i\n", (a++) ); 10 printf("b++ = %i\n", (b++) ); 11 12 a = false; 13 b = true; 14 printf("++a = %i\n", (++a) ); 15 printf("++b = %i\n", (++b) ); 16 17 a = false; 18 b = true; 19 printf("!a = %i\n", !a); 20 printf("!b = %i\n", !b); 21 22 a = false; 23 b = true; 24 printf("a^1 = %i\n", a^1); 25 printf("b^1 = %i\n", b^1); 26 27 28 //lol. 29 a = false; 30 b = true; 31 printf("(1 - (bool)a*-1) = %i\n", 1 - (bool)(a*-1)); 32 printf("(1 - (bool)b*-1) = %i\n", 1 - (bool)(b*-1)); 33 }

a = 0
b = 1
a++ = 0 //nope
b++ = 1 //nope
++a = 1 //nope
++b = 1 //nope
!a = 1 //yes
!b = 0 //yes
a^1 = 1 //yes
b^1 = 0 //yes
1 - (bool)a*-1 = 1 //yes
1 - (bool)b*-1 = 0 //yes... lols

torhu

With the postfix operators you have to increment and print them in two different statements, otherwise you get the original value ;)

But it looks like bools are limited to be either 0 or 1. I guess b + 1 would be 1?

By the way, what compiler version did you use?

Arthur Kalliokoski

What possible reason would you have to increment a bool anyway? Either set it to true or false, anything else is madness. Using ischar() as a number base makes about as much sense.

Elias

Well, looking at it from C it makes sense - there bool is the same as int and anything except zero means true. So if x is 1 and you do x++ it gets 2, which is still true.

It is stupid that they allowed ++ for bool in C++, but so are 1000 other things in C++, so I don't see anything special here :P

Chris Katko

I forgot to mention I'm running GCC. I don't recall the version, it's in the newer (maybe experimental?) branch which is necessary for proper c++14 (or whatever) support. I don't recall which, it's been a long time since I had to install it.

Mark Oates
Elias said:

Well, looking at it from C it makes sense

Why not x-- then?

As it is, you can flip false to true, or true to true, but not true to false. I would think the operators should be symmetrical, or not at all.

Arthur Kalliokoski
Elias said:

So if x is 1 and you do x++ it gets 2, which is still true.

But why would you do that with a bool, as opposed to some sort of stack pointer or ring buffer? Not to mention the wraparound, which is admittedly huge.

Peter Hull
torhu said:

By the way, what compiler version did you use?

I used MSVC, clang and gcc (not sure of the latest versions but all recent)

I suppose if you view bool as a one-bit arithmetic type then incrementing true is an overflow and that results in undefined behaviour - so the value could be anything.

And I suppose if you incremented something N times and decremented it N times you might expect to be back where you started, which can't be guaranteed for bool so they disabled '--'.

Maybe there was some reason for it back when they wrote the spec and maybe it just slipped through the net?

[edit] The fact that it's post increment gives it one possible use, though it's not hard to find alternatives:

void printlist(int n) {
 bool comma = false;
 for (int i = 0; i < n; ++i) {
  if (comma++) {
   cout << ',';
  }
  cout << i;
 }
}

The original example was here using C++ ranged for statement which makes a bit more sense.

torhu

I really don't understand why they added a separate function for just that use case, though...

bamccaig

I'm of the opinion that if a sensible meaning can be defined for an operator then it should be. I like being able to make code terse and operators are the best way to achieve that from the language or a global library. I don't see this as a problem at all, as long as the results are defined. If anything, it's a WTF to me that you cannot decrement. It's no surprise to most of us that a boolean type is typically represented by a 0/^0/!0 byte or bit. And we all understand what the result would be of incrementing those. It may not entirely make sense logically, but at the same time a useful meaning can be applied to and derived from it.

???

Chris Katko

I suppose if you view bool as a one-bit arithmetic type then incrementing true is an overflow and that results in undefined behaviour - so the value could be anything.

But we have tons of defined overflow scenarios. Unsigned overflows, signed overflows, float overflows. It seems strange they would just leave that one alone.

My opinion--and it's about as valuable as that--is that the more things that "don't immediately make sense" the more a programmer has to keep in his mind at all times while programming. And the more balls a programmer has to juggle at once, the more likely you hit create an error.

I'm sure there's some brain function / sign-of-intelligence that corresponds to how many ideas a person can have in their brain at one time. And the more taken up by the programming language, the less available for comprehending the task at hand. Which is why many people solve complex problems outside of code... by solving the problem separated from implementing that problem, you free up some "slots" in your brain to help take a "too big to fit" problem and hopefully fit it.

Quote:

[edit] The fact that it's post increment gives it one possible use, though it's not hard to find alternatives:

Actually, have you tested for an error in that code? What happens if you increment a bool 65536 times? Does it eventually wrap a 8/16/32/64-bit integer around to zero?

torhu

I compiled this as C++ in VS 2015, no optimizations:

void incbool(bool b)
{
  b++;
}

And got this:

?incbool@@YAX_N@Z (void __cdecl incbool(bool)):
  00000000: 55                 push        ebp
  00000001: 8B EC              mov         ebp,esp
  00000003: 51                 push        ecx
  00000004: 8A 45 08           mov         al,byte ptr [ebp+8]
  00000007: 88 45 FF           mov         byte ptr [ebp-1],al
  0000000A: C6 45 08 01        mov         byte ptr [ebp+8],1
  0000000E: 8B E5              mov         esp,ebp
  00000010: 5D                 pop         ebp
  00000011: C3                 ret

It's just copied, and then set to true.

Elias

All 4 of gcc, clang, g++, clang++ produce the same asm output for C/C++ code (simply moving the value 1 into the variable). So actually C's ++ operator behaves the same on a bool as C++'s.

torhu

Yeah, I get get same result in VS 2015. Only the name mangling of the function changes, the assembly is otherwise identical. I guess VS finally supports C99 bool, then.

Andrei Ellman
Elias said:

Well, looking at it from C it makes sense - there bool is the same as int and anything except zero means true. So if x is 1 and you do x++ it gets 2, which is still true.

And this, boys and girls, is why you should never use bitwise operators when you should use logical operators.

Case in point:

#SelectExpand
1 2int bitmask1 = 0x02; 3int bitmask2 = 0x38; 4 5bool somefunc1(int flags) 6{ 7 return flags & bitmask1; 8} 9 10bool somefunc2(int flags) 11{ 12 return flags & bitmask2; 13} 14 15void blah(int someflags) 16{ 17 if(somefunc1(someflags) & somefunc2(someflags)) 18 { 19 // bitwise AND 20 // As long as bitmask1 and bitmask2 don't share any flags, this will never be true. 21 } 22 23 if(somefunc1(someflags) && somefunc2(someflags)) 24 { 25 // Logical AND 26 // This will be true if someflags contains at least one flag in bitmask1 and one flag in bitmask2. 27 // But in cases where we know all bools will have the same numeric value for 'true', this will be slower than a bitwise AND. 28 } 29}

Here, if bools are treated like ints, the two if()s will behave differently. However, you could create a StrictBool class that behaves like a bool should. All operators will be overloaded with versions that use C++'s 'explicit' keyword with StrictBool-paramaters to prevent implicit casting, and there will be non-explicit versions of the operators that for each paramater, regardless of it's type, do something like value = (paramater?true:false) . In this case, both if()'s in the above code will be equivalent if the functions return StrictBools.

torhu

Yeah ;D

{"name":"636x460design_01.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/8\/48bed991ae72aac26032315a4ba6c62b.jpg","w":636,"h":460,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/8\/48bed991ae72aac26032315a4ba6c62b"}636x460design_01.jpg

Mark Oates

I ran some rudimentary (uncomprehensive) tests for performance between either several bool types or bitwise on an int.

Bitwise was a bit slower.

...

:D

No, but actually it was a bit slower. Only by about ~7% or something, though.

torhu

You should be careful with that kind of thing. Many simple operations require only one cycle on the CPU to do. And if you are comparing ints to bools on a PC (32 or 64 bits), you are probably comparing 32-bit types to 8-bit types. Which one is faster depends on what you do with. You could be comparing an operation to one that's different in either implementation, purpose, or both. Just saying :P

Bruce Perry

Isn't it the case that the compiler ensures that bools always have a 0 or a 1 stored in their memory location?

I think Visual Studio warns if an int is implicitly cast to bool, and the wording of the warning suggests that there will be a performance hit from the operation of constraining its value.

Mark Oates

Since ++ just copies it and sets it to true, then there's no reason not to include -- to copy and set to false.

Note: my actual position is that the operators should not be used at all on bool.

torhu said:

You should be careful with that kind of thing. Many simple operations require only one cycle on the CPU to do. And if you are comparing ints to bools on a PC (32 or 64 bits), you are probably comparing 32-bit types to 8-bit types. Which one is faster depends on what you do with. You could be comparing an operation to one that's different in either implementation, purpose, or both. Just saying :P

All of that's probably true :P

Arthur Kalliokoski

Since ++ just copies it and sets it to true, then there's no reason not to include -- to copy and set to false.

It doesn't even need to copy, just set.

torhu

It has to copy, that's the whole point of postincrement.

Fuck Matthew Leverton, just fuck him.

Arthur Kalliokoski

Write out your truth table and all possible outcomes (4 of them).

GullRaDriel
torhu said:

Fuck Matthew Leverton, just fuck him.

Bad thread ?

Bruce Perry

Arthur, the operator needs to return the old value of the variable from before it was set to true. For example:

bool munge(bool &x) {
    return x++;
}

That function will set x, but it will also return x's old value. To do that, it has to copy it.

Granted the compiler could optimise that away if the x++ appears as a statement with its value unused.

Andrei Ellman

That function will set x, but it will also return x's old value. To do that, it has to copy it.

Now, if x is some large class with an overloaded '++' operator, ++x and x++ can make all the difference, as copying would take longer.

Johan Halmén

{"name":"609921","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/a\/8a20a909009bfcd5bfee645bece22df7.png","w":474,"h":474,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/a\/8a20a909009bfcd5bfee645bece22df7"}609921

bamccaig

:D

Thread #615840. Printed from Allegro.cc