15

Does if (static_cast<bool>(x)) make sense for some type of x?

Obviously if x is a bool, static_cast is not required.

If x is a raw pointer or std::unique_ptr or std::shared_ptr, then if (x) is alright (especially since std::unique_ptr and std::shared_ptr both have a bool operator). Maybe if (x != nullptr) might be better.

If x is an int, I guess if (x != 0) is preferred.

If x is a double, I guess if (x != 0.0) is preferred (although checking for exact floating point values has its own issues).

If x is some enum, if (x != E()) or if (x != E::whatever) probably is better than static_cast<bool>.

Are there any reasons to use if (static_cast<bool>(x)) for custom types (structs or classes) convertible to bool?

AFAIK the C++ Core Guidelines do not mention static_cast<bool> explicitly. I'm aware of following discussions: if (static_cast<bool>(x)) vs if (x) (which covers pointers only) and int to bool casting

Jens
  • 187
  • 8
  • ... but then again, not in the context of `if` which will use the `explicit operator bool` without the the need for a cast. – Ted Lyngmo Jul 10 '23 at 15:25
  • 5
    In an `if`, `while`, or `for` statement, the controlling expression is ["contextually converted to `bool`"](https://en.cppreference.com/w/cpp/language/implicit_conversion). In that context there is no need for a cast, even if the type has a conversion to `bool` that's marked `explicit`. – Pete Becker Jul 10 '23 at 15:35
  • 3
    `if (static_cast(x))` is equivalent to `if (x)`, even for types with `explicit operator bool`. – Jarod42 Jul 10 '23 at 15:36
  • I guess you might if you're interacting with a C API that return truth values as `int` ? `if(static_cast(selected))` is probably no worse than `if(selected != 0)` (what does selected equals to 0 means?) in this case. But the preferred way would be simply `if(selected)`. – Lærne Jul 10 '23 at 15:36
  • "If `x` is some enum, `if (x != my_enum::whatever)` probably is better than `static_cast`." -> there might not be an enumeration in the enum with value 0 though, so your "probably better" style might not be an option. `if (my_enum)` - for an enum class - won't compile without the `static_cast`. – Tony Delroy Jul 10 '23 at 15:50
  • @Tony If `my_enum` has no value equal to 0, then no instance of that enum should ever be 0. — You *could* still create one using `my_enum()`, but you can then also do the same in the comparison inside the `if` conditional. – Konrad Rudolph Jul 10 '23 at 16:01
  • how is this different from https://stackoverflow.com/q/58674726/4117728 ? "Covers pointers only" is the answers, but that doesnt really make this a different question – 463035818_is_not_an_ai Jul 10 '23 at 16:37
  • @KonradRudolph: "no instance of that enum should" - perhaps in the world of your own coding standards, but that's not inherent in C++. `my_enum{}` creates exactly such an instance. As a concrete example of when a zero value might be valid but having no need of a matching enumeration - if the enum is used to store a bitwise OR of 2^N flag values (i.e. 1, 2, 4, 8...), there may be no more reason to insist of a zero value than any multi-bit value such as 3, 5, 6, 7, 9 etc. – Tony Delroy Jul 10 '23 at 16:38
  • @TonyDelroy You seem to have read only the first sentence of my comment, not the rest, which already addresses this. – Konrad Rudolph Jul 10 '23 at 16:39
  • @TonyDelroy the enumerators is only the named values of the enum type, but the underlying type has many more values. Im not even sure if you can define an enum which has not `0` within its range – 463035818_is_not_an_ai Jul 10 '23 at 16:40
  • @KonradRudolph: "already addresses this" - you address that a 0 value *could* be created without an enumeration, but only after asserting that instances *should* never have such a value: it's that "should" part that I was contesting, with an illustrative use case. – Tony Delroy Jul 12 '23 at 10:30

2 Answers2

18

Does if (static_cast<bool>(x)) make sense for some type of x?

Yes for enum class:

enum class E {
    A = 1
};

E e = E::A;
if (e) {} // KO
if (static_cast<bool>(e)) {} // OK

For regular struct/classes, if (static_cast<bool>(x)) is equivalent to if (x), even for types with explicit operator bool, so you can use the later.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • This is of course the right answer. Can't believe I didn't think of that case. I've used it a lot :-) – Ted Lyngmo Jul 10 '23 at 16:08
  • 8
    Besides arguably being a questionable enum class, wouldn’t you prefer an explicit check here, same as for `int` (i.e. `if (e != E())`? I know *I* would. – Konrad Rudolph Jul 10 '23 at 16:23
  • Thanks, @KonradRudolph, I didn't have this option in mind comparing some enum value to a zero-initialized one. I edited my question, adding your suggestion. – Jens Jul 10 '23 at 18:37
  • 1
    Thanks, @Jarod42, for pointing out that enum classes cannot be used like traditional enums in `if` statements. – Jens Jul 10 '23 at 18:41
  • `explicit operator bool` applies to other contexts similar to `if()`, notably `while()` and the second component of `for(;;)`. – iBug Jul 11 '23 at 12:08
  • Can you please add a reference for this behavior? – ryanwebjackson Aug 07 '23 at 22:11
12

Are there any reasons to use if (static_cast<bool>(x)) for custom types (structs or classes) convertible to bool?

Not often. Even classes only explicitly convertible to bool will convert to bool in that context.

struct Foo {
    explicit operator bool() const { return true; }
};

int main() {
    Foo f;
    if(f) {}    // compiles fine
}

If you however have a class with multiple user-defined conversions ...

struct Foo {
    explicit operator bool() const { return true; }
    operator int() const { return 0; }              // risky non-explicit
};

... you may want to clarify exactly which one you aim to use.

user2357112
  • 260,549
  • 28
  • 431
  • 505
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Even for evil `Foo`, it is unneeded [Demo](https://godbolt.org/z/fPrarjojq). – Jarod42 Jul 10 '23 at 15:42
  • @Jarod42 :-) I know. The aim was for clarity. It could be a messy class where people add and remove `operator`s and suddenly `bool` is gone and then the implicit `int` kicks in. – Ted Lyngmo Jul 10 '23 at 15:44
  • 4
    @TedLyngmo: But `static_cast` will happily chain a user-defined conversion to `int` followed by a standard conversion to `bool`, just like the contextual conversion would. – Ben Voigt Jul 10 '23 at 16:02
  • 1
    @BenVoigt Yes, it's for clarity of the intent for the reader of the code, but sure, the evil implicit conversion will still kick in. The only hope is that the explicit `static_cast` makes someone pay extra attention there when searching for the bug. :) – Ted Lyngmo Jul 10 '23 at 16:07