#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, anecan be implicitly converted to a typeTif 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 expressioneappearing in such a context is said to be contextually converted tobooland 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). -
forstatement,for(;t;) //..., and -
whilestatement,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 theforandwhilestatements (6.5)." -
dostatement:do {//...} while (t);(6.5.2 p1). -
static-assert_declaration :static_assert(t);(note you will needconstexprhere) (7 p4). -
Exception specification:
SomeType foo() noexcept(t);(note you will needconstexprhere) (15.4 p1). -
NullablePointer concept: Any type
Pthat can be used where the standard library requires a type fulfilling the NullablePointer concept, it is required that an instance ofPcan be contextually converted tobool(17.6.3.3 p3). -
Any algorithm in the
<algorithm>header that takes a template parameter namedPredicate, then for an instancepredof 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 typeboolmust convert totrueif the first argument is less than the second, andfalseotherwise. (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).
nice catch!
ReplyDeleteHi Chris,
ReplyDeleteI organise a C++ Meet up in London would you be interested in sharing your knowledge by giving a talk?
Hi Jason, I'll take that as a compliment (or you're getting desperate :) ), but I don't think I'm at that sort of level yet.
DeleteI do work pretty close by though, and some of my colleagues have been and said good things, so I may come along to the next one and watch (the problem is, it takes me at least an hour to get home afterwards).
For anyone else interested: event link.