The other answers cover how it works, but I think you should be told why it was added to C++.
A smart pointer usually has a conversion to bool
so you can do this:
std::shared_ptr<int> foo;
if (foo) {
*foo = 7;
}
where if(foo)
converts foo
to bool
. Unfortunately:
int x = foo+2;
converts foo
to bool
, then to int
, then adds 2
. This is almost always a bug. This is permitted because while only one user defined conversion is done, a user defined conversion followed by a built in conversion can silently occur.
To fix this programmers would do crazy things like add:
struct secret {
void unused();
};
struct smart_ptr {
using secret_mem_ptr = void(secret::*)();
operator secret_mem_ptr() const { return 0; }
};
and secret_mem_ptr
is a secret pointer to member. A pointer to member has a built in conversion to bool
, so:
smart_ptr ptr;
if (!ptr) {
}
"works" -- ptr
is convert to secret_mem_ptr
, which then is convered to bool
, which is then used to decide which branch to take.
This was more than a bit of a hack.
They added explicit
on conversion operators to solve this exact problem.
Now:
struct smart_ptr {
explicit operator bool() const { return true; }
};
doesn't permit:
smart_ptr ptr;
int x = 3 + ptr;
but it does permit:
if (ptr) {
}
because the rules were hand-crafted to support exactly that use case. It also doesn't permit:
bool test() {
smart_ptr ptr;
return ptr;
}
here, you have to type:
bool test() {
smart_ptr ptr;
return (bool)ptr;
}
where you explicitly convert ptr
to bool
.
(I am usually really against C-style casts; I make an exception in the case of (bool)
).