C++ tidbit #3: Contextual Conversion
Warmup: explicit constructors
When you mark a cast operator as explicit:
struct C {
explicit operator bool() { return true; }
};
(yes, that is a silly implementation) you're saying that implicit casts will fail to compile:
bool b1 = c; // error
bool b2 = c==true; // error
bool b3 = static_cast<bool>(c); // explicit cast - success
This is generally considered a good practice, as implicit casts are a gaping hole in C++ strong-type system. If, for example, you passed a wrong argument to a function - you want the compiler to err and help you catch it, and not implicit-cast to hide away the source of the error and sneak up on you in surprising ways later.
Some Surprises
So, what happened in the 2nd line here?
if (c == true) {} // compilation error, as expected
if (c) {} // success ?!
And here??
while(c) {} // success !?
for (int i=0; c ; ++i) {} // success !?!
And, oh my, here?
bool b4 = c || false // success !!?
bool b5 = c ? true : false; // success !??!
No explicit casts are anywhere to be seen. Shouldn't all these implicit casts be forbidden??
You can fiddle with this live code in various compilers here .
Enter Contextual Conversion
`bool` is special.
There are specific locations within the C++ syntax that require a bool type. In all the surprise-success cases above, `c` appears in such a place (go check!).
In these places a slightly different set of rules kicks in, and the term employed is contextual conversion (not casting!) to bool. In a nutshell: existing cast-operators to bool are considered, with `explicit` ignored. Details and some delicate diffs between C++ versions here .
Final Musing
This is a fine example of a good intention on the road to hell. Sometime during C++'s evolution, its designers wished to provide this convenience to developers - and not have them type out casts to bool where it would seem clear from the context that such a cast must be present.
I would happily trade the extra head-scratches this had caused me for some extra typing and reading. The same goes for many, many other C++ dark corners too. Some modern languages (notably Rust) learnt that lesson well, and allow no implicit casting of any kind.
Signal Processing and Software Engineer | Motivated by creating value for the end user | Interested in fault tolerance and flexibility of software | Keen language learner and language transmission activist
2 年OMG! The horror! Thanks for highlighting this nuance(?) (read: nuisance?)