This post is about one gotcha in Boost.Optional library. When starting to use it, you might get the impression that when you try to put optional<T> where T is expected, you will get a compile-time error. In most of the cases it is exactly so, but sometimes you may get really surprised.

Let’s consider an example similar to the one described in my other post.

double Flight_plan::weight() { if (Impl* impl = get_impl()) { return impl->compute_weight(); } else { DO_WHAT; // ??? } }

Once in a while, it is possible to get a null pointer, and for some reason you choose not to signal it via an exception. One idea to reflect this situation is to use Boost.Optional:

boost::optional<double> Flight_plan::weight() { if (Impl* impl = get_impl()) { return impl->compute_weight(); } else { return boost::none; } }

Sooner or later someone will use this function like this:

bool is_too_heavy(Flight_plan const& p) { return p.weight() > p.aircraft().max_weight(); }

You might be thinking that at this point the compiler will detect a type mismatch and signal an error. This is what I was thinking when writing my other post, and I was wrong.

Look at this line:

return impl->compute_weight();

Function Impl::compute_weight obviously returns type double , but the type expected by the return statement is optional<double> . Nonetheless, the line compiles because optional<T> defines a converting constructor from T . This is very convenient in the cases like ours here, but it also implies some consequences.

Another thing that is not obvious and surprises some people is that optional<T> is LessThanComparable (whenever T is LessThanComparable ). In this comparison, the value of boost::none is considered as a unique value less than any other value of T . This is a sort of lexicographical order.

These two features combined together render a “mixed” comparison a valid operation. Expression:

p.weight() > p.aircraft().max_weight();

Is interpreted as:

p.weight() > optional<double>{p.aircraft().max_weight()};

In this case the optional on the right-hand side is never “empty”, while the one on the left-hand side sometimes is, and in this case the comparison returns false , which means “aircraft is not too heavy”!