optional lite is a single-file header-only library to represent optional (nullable) objects and pass them by value. The library is a variant of std::optional [1,2] for use with C++98 and later and with Visual C++ 6 (VC6).
Contents
- Example usage
- In a nutshell
- License
- Dependencies
- Installation
- Synopsis
- Comparison of std::optional, optional lite and Boost.Optional
- Reported to work with
- Implementation notes
- Notes and references
#include "optional.hpp"
#include <cstdlib>
#include <iostream>
using nonstd::optional;
using nonstd::nullopt;
optional<int> to_int( char const * const text )
{
char * pos = NULL;
const int value = strtol( text, &pos, 0 );
return pos == text ? nullopt : optional<int>( value );
}
int main( int argc, char * argv[] )
{
char * text = argc > 1 ? argv[1] : "42";
optional<int> oi = to_int( text );
if ( oi ) std::cout << "'" << text << "' is " << *oi;
else std::cout << "'" << text << "' isn't a number";
}
prompt>g++ -Wall -Wextra -std=c++03 -I.. -o to_int.exe to_int.cpp && to_int x1
'x1' isn't a number
optional lite is a single-file header-only library to represent optional (nullable) objects and pass them by value. The library is a variant of std::optional [1,2] for use with C++98 and later and with Visual C++ 6 (VC6). In turn, std::optional is inspired on Boost.Optional [3].
Features and properties of optional lite are ease of installation (single header), default and explicit construction of an empty optional, construction and assignment from a value that is convertible to the underlying type, copy-construction and copy-assignment from another optional of the same type, testing for the presence of a value, operators for unchecked access to the value (pointer or reference), value() and value_or() for checked access to the value, relational operators, swap() and make_optional() to create an optional of the proper type.
Not provided are reference-type optionals, and C++11 capabilities such as move semantics and in-place construction. optional lite doesn't handle overloaded address of operators.
For more examples, see this answer on StackOverflow [4] and the quick start guide [5] of Boost.Optional (note that its interface differs from optional lite).
optional lite uses the Boost Software License.
optional lite has no other dependencies than the C++ standard library.
optional lite is a single-file header-only library. Put optional.hpp
directly into the project source tree or somewhere reachable from your project.
Contents
Types in namespace nonstd
Interface of optional lite
Algorithms for optional lite
Macros to control alignment
Purpose | Type | Object |
---|---|---|
To be, or not | template< typename T > class optional; |
|
Disengaging | struct nullopt_t; | nullopt_t nullopt; |
Error reporting | class bad_optional_access; |
Kind | Method | Result |
---|---|---|
Construction | optional() | a nulled object |
optional( nullopt_t ) | a nulled object | |
optional( value_type const & value ) | initialized to value | |
optional( optional const & other ) | initialized to value of other | |
Destruction | ~optional() | destruct current content, if any |
Assignment | optional & operator=( nullopt_t ) | null the object; destruct current content, if any |
optional & operator=( optional const & rhs ) | assign the value of other; destruct current content, if any |
|
Swap | void swap( optional & other ) | swap with other |
State | operator bool() const | true if content is present (safe bool idiom) |
Content | value_type const * operator ->() const | pointer to current content (const); must contain value |
value_type * operator ->() | pointer to current content (non-const); must contain value |
|
value_type const & operator *() const | the current content (const ref); must contain value |
|
value_type & operator *() | the current content (non-const ref); must contain value |
|
value_type const & value() const | the current content (const ref); throws bad_optional_access if nulled |
|
value_type & value() | the current content (non-const ref); throws bad_optional_access if nulled |
|
value_type value_or( value_type const & default_value ) | the value, or default_value if nulled value_type must be copy-constructible |
Kind | Function |
---|---|
Relational operators | |
== | template< typename T > bool operator==( optional const & x, optional const & y ) |
!= | template< typename T > bool operator!=( optional const & x, optional const & y ) |
< | template< typename T > bool operator<( optional const & x, optional const & y ) |
> | template< typename T > bool operator>( optional const & x, optional const & y ) |
<= | template< typename T > bool operator<=( optional const & x, optional const & y ) |
>= | template< typename T > bool operator>=( optional const & x, optional const & y ) |
Comparison with nullopt | |
== | template< typename T > bool operator==( optional const & x, nullopt_t ) |
template< typename T > bool operator==( nullopt_t, optional const & x ) |
|
!= | template< typename T > bool operator!=( optional const & x, nullopt_t ) |
template< typename T > bool operator!=( nullopt_t, optional const & x ) |
|
< | template< typename T > bool operator<( optional const &, nullopt_t ) |
template< typename T > bool operator<( nullopt_t, optional const & x ) |
|
<= | template< typename T > bool operator<=( optional const & x, nullopt_t ) |
template< typename T > bool operator<=( nullopt_t, optional const & ) |
|
> | template< typename T > bool operator>( optional const & x, nullopt_t ) |
template< typename T > bool operator>( nullopt_t, optional const & ) |
|
>= | template< typename T > bool operator>=( optional const &, nullopt_t ) |
template< typename T > bool operator>=( nullopt_t, optional const & x ) |
|
Comparison with T | |
== | template< typename T > bool operator==( optional const & x, const T& v ) |
template< typename T > bool operator==( T const & v, optional const & x ) |
|
!= | template< typename T > bool operator!=( optional const & x, const T& v ) |
template< typename T > bool operator!=( T const & v, optional const & x ) |
|
< | template< typename T > bool operator<( optional const & x, const T& v ) |
template< typename T > bool operator<( T const & v, optional const & x ) |
|
<= | template< typename T > bool operator<=( optional const & x, const T& v ) |
template< typename T > bool operator<=( T const & v, optional const & x ) |
|
> | template< typename T > bool operator>( optional const & x, const T& v ) |
template< typename T > bool operator>( T const & v, optional const & x ) |
|
>= | template< typename T > bool operator>=( optional const & x, const T& v ) |
template< typename T > bool operator>=( T const & v, optional const & x ) |
|
Specialized algorithms | |
swap | template< typename T > void swap( optional & x, optional & y ) |
create | template< typename T > optional make_optional( T const & v ) |
If optional lite is compiled as C++11 or later, C++11 alignment facilities are used for storage of the underlying object. When compiled as pre-C++11, optional lite tries to determine proper alignment itself. If this doesn't work out, you can control alignment via the following macros. See also section Implementation notes.
-Doptional_FEATURE_MAX_ALIGN_HACK=0
Define this to 1 to use the max align hack for alignment. Default is 0.
-Doptional_FEATURE_ALIGN_AS=pod-type
Define this to the pod-type you want to align to (no default).
-Doptional_FEATURE_ALIGN_AS_FALLBACK=pod-type
Define this to the pod-type to use for alignment if the algorithm of optional lite cannot find a suitable POD type to use for alignment. Default is double.
optional lite is inspired on std::optional, which in turn is inspired on Boost.Optional. Here are the significant differences.
Aspect | optional | optional lite | Boost.Optional |
---|---|---|---|
Move semantics | yes | no | no |
noexcept | yes | no | no |
Hash support | yes | no | no |
Throwing value accessor | yes | yes | no |
Literal type | partially | no | no |
In-place construction | emplace, tag in_place | no | utility in_place_factory |
Disengaged state tag | nullopt | nullopt | none |
optional references | no (optionally) | no | yes |
Conversion from optional<U> to optional<T> |
no | no | yes |
Duplicated interface functions 1) | no | no | yes |
Explicit convert to ptr (get_ptr) | no | no | yes |
- is_initialized(), reset(), get().
optional lite is reported to work with the following compilers:
- Visual C++ 6 SP6 (VS6), VC10, (VS2010), VC11 (VS2012), VC12 (VS2013), ...
- GNUC 4.8.1 with -std=c++98, -std=c++03, -std=c++11, -std=c++1y
- clang 3.4 with -std=c++03, -std=c++11 (on Travis)
optional lite reserves POD-type storage for an object of the underlying type inside a union to prevent unwanted construction and uses placement new to construct the object when required. Using non-placement new (malloc) to obtain storage, ensures that the memory is properly aligned for the object's type, whereas that's not the case with placement new.
If you access data that's not properly aligned, it 1) may take longer than when it is properly aligned (on x86 processors), or 2) it may terminate the program immediately (many other processors).
Although the C++ standard does not guarantee that all user-defined types have the alignment of some POD type, in practice it's likely they do [6, part 2].
If optional lite is compiled as C++11 or later, C++11 alignment facilities are used for storage of the underlying object. When compiling as pre-C++11, optional lite tries to determine proper alignment using meta programming. If this doesn't work out, you can control alignment via three macros.
optional lite uses the following rules for alignment:
-
If the program compiles as C++11 or later, C++11 alignment facilities are used.
-
If you define -Doptional_FEATURE_MAX_ALIGN_HACK=1 the underlying type is aligned as the most restricted type in
struct max_align_t
. This potentially wastes many bytes per optional if the actually required alignment is much less, e.g. 24 bytes used instead of the 2 bytes required. -
If you define -Doptional_FEATURE_ALIGN_AS=pod-type the underlying type is aligned as pod-type. It's your obligation to specify a type with proper alignment.
-
If you define -Doptional_FEATURE_ALIGN_AS_FALLBACK=pod-type the fallback type for alignment of rule 5 below becomes pod-type. It's your obligation to specify a type with proper alignment.
-
At default, optional lite tries to find a POD type with the same alignment as the underlying type.
The algorithm for alignment of 5. is:
- Determine the alignment A of the underlying type using
alignment_of<>
. - Find a POD type from the list
alignment_types
with exactly alignment A. - If no such POD type is found, use a type with a relatively strict alignment requirement such as double; this type is specified in
optional_FEATURE_ALIGN_AS_FALLBACK
(default double).
- Determine the alignment A of the underlying type using
Note that the algorithm of 5. differs from the one Andrei Alexandrescu uses in [6, part 2].
The class template alignment_of<>
is gleaned from Boost.TypeTraits, alignment_of [9]. The storage type storage_t<>
is adapted from the one I created for spike-expected, expected lite [11].
For more information on constructed unions and alignment, see [6-10].
[1] Fernando Cacciola, Andrzej Krzemieński. A proposal to add a utility class to represent optional objects (Revision 5).
[2] Andrzej Krzemieński. optional (nullable) objects for C++14. Reference implementation on GitHub.
[3] Fernando Cacciola. Boost.Optional library.
[4] StackOverflow. How should one use std::optional?. Answer by Timothy Shields. 31 May 2013.
[5] Fernando Cacciola. Boost.Optional Quick start guide.
[6] Andrei Alexandrescu. Generic: Discriminated Unions part 1, part 2, part 3. April 2002.
[7] Herb Sutter. Style Case Study #3: Construction Unions. GotW #85. 2009
[8] Kevin T. Manley. Using Constructed Types in C++ Unions. C/C++ Users Journal, 20(8), August 2002.
[9] StackOverflow. Determining maximum possible alignment in C++.
[10] Boost.TypeTraits, alignment_of ( code ).
[11] Martin Moene. spike-expected (expected-lite.hpp).