54

[This question is related to but not the same as this one.]

If I try to use values of certain types as boolean expressions, I get a warning. Rather than suppress the warning, I sometimes use the ternary operator (?:) to convert to a bool. Using two not operators (!!) seems to do the same thing.

Here's what I mean:

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?

So, does the double-not technique really do the same thing? Is it any more or less safe than the ternary technique? Is this technique equally safe with non-integral types (e.g., with void * or double for T)?

I'm not asking if !!t is good style. I am asking if it is semantically different than t ? true : false.

Community
  • 1
  • 1
jwfearn
  • 28,781
  • 28
  • 95
  • 122
  • 3
    When I see a line like "b = t ? true : false;" I'm always tempted to replace it with the line "b = t". There's already an implicit cast to bool, why mince semantics? – Greg D Oct 15 '08 at 20:26
  • 3
    as the Q says, because b=t gives a warning – jwfearn Oct 15 '08 at 20:50
  • 2
    interesting how many people are against `!!` on subjective basis. double negation is *the* idiomatic cast-to-bool vehicle in JavaScript, and if javascripters get it, I'd expect C++ users would too. – just somebody Jan 12 '10 at 12:08
  • 2
    double negation is common in most of the scripting languages http://stackoverflow.com/questions/524658/what-does-mean-in-ruby So, usage in a high level, understandable code(at least by writer himself) is stricly prohibited.. :) – vprajan Mar 18 '10 at 09:24
  • @GregD One case would be when assigning value to a bit-field flag in a struct. Your solution would truncate (at least in some compilers), while the rest offered here would set the flag to the relevant truth value. Assuming that the compiler will do the right thing (for you) is not the smart thing. And setting the bit-field type to boolean doesn't change this (at least with the compiler I'm dealing with). Undefined behaviour. – Jostikas Sep 15 '17 at 07:28
  • @GregD `b = t ? true : false;` has an **explicit** cast of `t` to bool. `b = t;` has an **implicit** cast. Although I prefer `b = static_cast(t);` when I have to be explicit – Caleth May 17 '20 at 11:17

18 Answers18

84

The argument of the ! operator and the first argument of the ternary operator are both implicitly converted to bool, so !! and ?: are IMO silly redundant decorations of the cast. I vote for

b = (t != 0);

No implicit conversions.

fizzer
  • 13,551
  • 9
  • 39
  • 61
42

Alternatively, you can do this: bool b = (t != 0)

Dima
  • 38,860
  • 14
  • 75
  • 115
  • 4
    I always use this one because I think it most clearly expresses the intent. It's effectively what the compiler is doing in the case that generates the warning, but is explicit about it. The !! seems hacky to me. – rmeador Oct 15 '08 at 19:52
  • Doesn't work if t is an object whose class provides operator (bool), whereas the other suggestions do. – Jules May 07 '16 at 07:02
32

Careful!

  • A boolean is about truth and falseness.
  • An integer is about whole numbers.

Those are very distinct concepts:

  • Truth and falseness is about deciding stuff.
  • Numbers are about counting stuff.

When bridging those concepts, it should be done explicitly. I like Dima's version best:

b = (t != 0);

That code clearly says: Compare two numbers and store the truth-value in a boolean.

edgar.holleis
  • 4,803
  • 2
  • 23
  • 27
6

All valid techniques, all will generate the same code.

Personally, I just disable the warning so I can use the cleanest syntax. Casting to a bool is not something I'm worried about doing accidentally.

  • 4
    Yeah, thank Microsoft for giving us warnings for clear and idiomatic C code. – Kristopher Johnson Oct 15 '08 at 19:42
  • I do wonder what made them add the warning; someone must've been doing something *really* dumb... –  Oct 15 '08 at 19:45
  • maybe it has implications on certain target architectures? MS doesn't say other than the warning for normal casts and conversions is "by design" – jwfearn Oct 15 '08 at 20:57
  • @MikeF the warning is there so the compiler can "WARN" you about something you might not be intending to do. disabling the warning might be "clean" but might result to typos or unintented errors. (like passing a long to a function that wanted a bool?) – moogs Oct 16 '08 at 03:20
  • I recently saw a piece of code that intended to compare two pointers, but in fact the pointers were implicitly cast into bool, so you may guess it did not work very well. I am against blanket disabling of warnings unless there is a compiler bug involved (as was the case with some VC++ 6.0 warnings) – Gorpik Oct 16 '08 at 07:49
  • The warning is quite useful when you by mistake assigned the integer a to b instead of the boolean c to b. – Anders Sandvig Oct 24 '08 at 12:07
  • @jwfearn It says the warning for an explicit cast is the same as an implicit cast "by design". The warning is there because simply casting to boolean is bad programming practice. Converting to boolean using a bool b = (a != 0) communicates exactly your intent. Casting to boolean may bypass having to worry about the type, but causes maintainability issues. – iheanyi Oct 21 '14 at 16:40
6


Yes it is safe.


0 is interpreted as false, everthing else is true,
hence !5 comes out as a false
!0 comes out as true
so !!5 comes out as true

EvilTeach
  • 28,120
  • 21
  • 85
  • 141
6

I would not use:

bool b = !!t;

That is the least readable way (and thus the hardest to maintain)

The others depend on the situation.
If you are converting to use in a bool expression only.

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

Then I would let the language do it for you:

if (t)
{
    doSomething();
}

If you are actually storing a boolean value. Then first I would wonder why you have a long in the first places that requires the cast. Assuming you need the long and the bool value I would consider all the following depending on the situation.

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.

Summary: Use what provides the most meaning for the context you are in.
Try and make it obvious what you are doing

m13r
  • 2,458
  • 2
  • 29
  • 39
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • the "let the language do it" (aka 'usual conversions') is what generates the warning. an example of when this might be necessary: struct C { void * hdl; void * get_hdl() { return hdl; } bool has_hdl() const { return hdl ? true : false; } – jwfearn Oct 15 '08 at 20:16
  • 7
    readability is in the eye of the beholder. for example, I consider prefix operators more readable than postfix operators, conciseness over verbosity, and dryness over duplication. (double) negation is a prefix operator (win), is shorter than the ternary (win), and can be perceived as a single operator whereas the ternary carries three distinct expressions (plus the operator syntax). – just somebody Jan 12 '10 at 12:31
4

Comparison to 0 doesn't work so well. Which comes back -- why !! vs. ternary?

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
Jay K
  • 129
  • 3
  • 1
    Is there any distinctive new information in this answer? If you decide to answer an older question that has well established and correct answers, adding a new answer late in the day may not get you any credit. If you have some distinctive new information, or you're convinced the other answers are all wrong, by all means add a new answer, but 'yet another answer' giving the same basic information a long time after the question was asked usually won't earn you much credit. – Jonathan Leffler May 25 '18 at 06:53
  • 1
    Yes. Nobody else identified that != 0 can often fail. – Jay K May 25 '18 at 13:09
3

I recommend never suppressing that warning, and never using a c cast (bool) to suppress it. The conversions may not always be called as you assume.

There is a difference between an expression that evaluates to true and a boolean of that value.

Both !! and ternary take getting used to, but will do the job similarly, if you do not want to define internal types with overloaded casts to bool.

Dima's approach is fine too, since it assigns the value of an expression to a bool.

tabdamage
  • 260
  • 1
  • 3
  • Care to come up with an example where that warning would help in any way? –  Oct 15 '08 at 19:50
  • well, you might be losing information in that cast. maybe you're porting the code from an environment in which no information is lost in this conversion. in that case, may you'd like to know about any lost bits. – wilhelmtell Oct 15 '08 at 19:56
  • 1
    Of course you're losing information. That's the entire point of converting to bool! – John Millikin Oct 15 '08 at 20:01
  • @wilhelmtell: What kind of environment doesn't lose information in int->bool? –  Oct 15 '08 at 20:22
  • @Mike: as code changes, the value you are converting to bool could be typedef'd, and thus the code generated might change. Also, there are compilers with signed and unsiged char as default, which could give different results. – tabdamage Oct 15 '08 at 20:32
  • @tabdamage: The type you're converting to bool has no effect on whether or not you get this warning, so that example doesn't work. And char signdness has no bearing on anything. –  Oct 15 '08 at 20:37
  • MS says (http://msdn.microsoft.com/en-us/library/b6801kcy.aspx) the warning is "by design" but they don't explain – jwfearn Oct 15 '08 at 20:59
2

If you're worried about the warning, you can also force the cast: bool b = (bool)t;

warren
  • 32,620
  • 21
  • 85
  • 124
  • 1
    actually that is exactly equivalent to bool b = t; and generates the same warning – jwfearn Oct 15 '08 at 19:46
  • Don't use C casts. C++ casts are there for a reason. Also, I didn't try this on my compiler, but I wouldn't expect it to generate any warning because you are explicitly asking the compiler to do something. Compilers usually only warn you when something implicit happens. – wilhelmtell Oct 15 '08 at 19:53
  • I never see the warning under GCC on my Ubuntu box when doing it this way – warren Oct 15 '08 at 19:58
  • @wilhelmtell: Give it a try; you'll find that VC++ *does* in fact warn you about '(bool)a', 'bool(a)' and 'static_cast(a)'. –  Oct 15 '08 at 19:59
  • @warren: Ah, the poster didn't mention that this is VC++ specific, tags edited accordingly. –  Oct 15 '08 at 20:04
  • Q is not necessarily VC++ specific (although that is where I tested it), I'm asking about the diff (if any) between !!x and x?true:false. I bet many compilers have similar warnings depending on your warning level. removed visualstudio tag – jwfearn Oct 15 '08 at 20:24
  • @jwfeam: If that's the question then you got your answer yonks ago (="no, there's no difference"). BTW, you'd lose the bet about other compilers emitting this (rather weird) warning. –  Oct 15 '08 at 20:30
  • @Mike F, you may be right, this could be a VC++ specific warning. Since I don't have access to all C++ compilers, I can only guess. But the Q isn't really about the warning, it was "is !! safe?". I posted a separate Q about the warning (and got some good answers too). – jwfearn Oct 16 '08 at 03:13
2

I really hate !!t!!!!!!. It smacks of the worst thing about C and C++, the temptation to be too clever by half with your syntax.

bool b(t != 0); // Is the best way IMHO, it explicitly shows what is happening.

Jim In Texas
  • 1,524
  • 4
  • 20
  • 31
1

!! may be compact, but I think it is unnecessarily complicated. Better to disable the warning or use the ternary operator, in my opinion.

Kristopher Johnson
  • 81,409
  • 55
  • 245
  • 302
0

I would use b = (0 != t) -- at least any sane person can read it easily. If I would see double dang in the code, I would be pretty much surprised.

0

Disable the warning.

Write for clarity first; then profile; then optimize for speed, where required.

Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
0

!! is only useful when you're using a boolean expression in arithmetic fashion, e.g.:

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

(Whose style is a different discussion.) When all you need is a boolean expression, the !! is redundant. Writing

bool b = !!extra;

makes as much sense as:

if (!!extra) { ... }
aib
  • 45,516
  • 10
  • 73
  • 79
0

One important reason of using the double negation technique, which no one yet mentioned, is performance. As it was pointed out this is basically a replacement of the

x = b ? 1 : 0;

statement, which may add substantial overhead if it evaluates to true in roughly half of the cases. CPU branch-prediction will not work well in such a situation, which would lead to branch misses quite often. Due to this the overhead compared with using

x = !!(b);

operation would be quite substantial, provided, of course, that this operation is executed sufficiently often.

-1

I recommend to use

if (x != 0)

or

if (x != NULL)

instead of if(x); it's more understandable and readable.

Marco M.
  • 252
  • 1
  • 4
-2

The double not feels funny to me and in debug code will be very different than in optimized code.

If you're in love with !! you could always Macro it.

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

(as an aside, the ternary operator is what I favor in these cases)

plinth
  • 48,267
  • 11
  • 78
  • 120
-4

I would use bool b = t and leave the compile warning in, commenting on this particular line's safety. Disabling the warning may bite you in the butt in another part of the code.

Paul Nathan
  • 39,638
  • 28
  • 112
  • 212
  • 5
    Leaving warnings that need to be ignored is counter productive; it leads you to miss other, more important warnings. A zero-warning policy is the best. – Mark Ransom Oct 15 '08 at 20:44
  • Yes, but disabling warnings is worse, it shuts down warnings that may be more important. As Edgar said above, bools are about truth-value, integers are about number. That distinction should be preserved somehow. – Paul Nathan Oct 15 '08 at 20:47