...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
One part of the interface is for modifying and setting the initial state of the object. It has to be able to say that
T
,
The default constructor stores no value. Other than that, we require that
the assignment and construction from a T
reflects the former, while assignment and construction of a special tag
value none
reflect the latter
need.
optional<int> o1; // contains no value optional<int> o2 = 2; // contains value 2 optional<int> o3 = none; // contains no value o1 = 1; // assign value 1 o2 = none; // assign a no-value o3 = {}; // assign a no-value
Inspecting the state of an optional object requires two steps:
This 'procedure' is characteristic of inspecting pointers in C++, therefore the pointer-like syntax was chosen to represent this.
void inspect (optional<string> os) { if (os) { // contextual conversion to `bool` read_string(*os); // `operator*` to access the stored value read_int(os->size()); // `operator->` as shortcut for accessing members } }
Also, similarly to pointers, if you access the value when it is not there,
you trigger undefined
behavior. This library detects and reports it via BOOST_ASSERT()
. This common property of pointers
and optional<>
has been formalized into a concept OptionalPointee
.
However, there is also the counter-intuitive part. All pointers embed shallow-copy semantics: when you copy a pointer, the pointed-to object stays at the same location and you can access it via either of the pointers. This is unlike optional objects where the represented value is copied along.
![]() |
Caution |
---|---|
Optional objects are not pointers. |
There is a similar difference in relational operations: they compare deeply
for optional<>
,
while they are shallow for pointers.
![]() |
Note |
---|---|
When you need a deep relational operations that work uniformly for |