#include <iostream> struct Testable { explicit operator bool() const { return true; } }; int main() { Testable t; if (t) std::cout << "Converted to true!\n"; }That is, it compiles and prints
Converted to true!
.
The new bit here is the
explicit
keyword. When I first saw an example like this, I expected to have to write
if (bool( t )) // ...If this was an
operator someOtherType()
, we t
say as an argument to a function accepting bool
, we would also have to write the conversion explicitly (it is the explicit
keyword, after all!).
What makes this work is this wording in The Standard, at Section 4
Standard conversions
, paragraph 3:
An expressionSo basically, in any kind of logical condition, ane
can be implicitly converted to a typeT
if and only if the declarationT t=e;
is well-formed, for some invented temporary variablet
(8.5). Certain language constructs require that an expression be converted to a Boolean value. An expressione
appearing in such a context is said to be contextually converted tobool
and is well-formed if and only if the declarationbool t(e);
is well-formed, for some invented temporary variablet
(8.5). The effect of either implicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion.
explicit operator bool()
can be called without having to write bool(...)
. This replaces the need for workarounds such as operator void*
, or The Safe bool
Idiom (if you were wondering why you wouldn't just use operator bool()
explicit
, that link will explain it).
I've been trying to enumerate all the cases in The Standard where it uses the wording "
contextually converted to bool
", but I may have missed some:
-
Negation:
!t
(5.3.1 p9). -
Logical AND:
t&&s
(5.14). -
Logical OR:
t||s
(5.15). -
Conditional operator:
t?"yup":"nope"
(5.16 p1). -
Selection statement (other than
switch
):if (t)
orif (Testable t{})
(6.4 p4). -
for
statement,for(;t;) //...
, and -
while
statement,while(t) //...
. The wording isn't used directly for these, and they are actually defined in section 6.5, but 6.4 p2 says "The rules for conditions apply both to selection-statements and to thefor
andwhile
statements (6.5)." -
do
statement:do {//...} while (t);
(6.5.2 p1). -
static-assert_declaration :static_assert(t);
(note you will needconstexpr
here) (7 p4). -
Exception specification:
SomeType foo() noexcept(t);
(note you will needconstexpr
here) (15.4 p1). -
NullablePointer concept: Any type
P
that can be used where the standard library requires a type fulfilling the NullablePointer concept, it is required that an instance ofP
can be contextually converted tobool
(17.6.3.3 p3). -
Any algorithm in the
<algorithm>
header that takes a template parameter namedPredicate
, then for an instancepred
of that type, it must supportpred(*first)
being contextually converted to typebool
. (25.1 p8)
Similarly, for aBinaryPredicate binary_pred
, it is required thatbinary_pred(*first1, *first2)
orbinary_pred(*first1, value)
can be contextually converted to typebool
. (25.1 p9) -
For any algorithm taking a comparator type
Compare
, for an instanceCompare comp
, the return value when contextually converted to typebool
must convert totrue
if the first argument is less than the second, andfalse
otherwise. (25.4 p2)
basic_ios
template, operator void*()
has been replaced with explicit operator bool()
. It is also used to simulate checking for NULL
in the Standard smart pointers, shared_ptr
and unique_ptr
. Have a look through these.
Note: I don't have the official ISO C++ Standard published 2011-09-01. I am looking at N3337, the first draft published
contextually converted to type bool
. This is corrected in the most recent c++14 draft N3691 (2013-05-16).
Let me make it entirely clear that the previous methods of achieving this behaviour (e.g.
operator void*()
) still work as ever. It's just there is now a nicer way (I consider it nicer in that it more clearly indicates intent, and actually does what you wanted).