optional lite - A C++17-like optional, a nullable object for C++98, C++11 and later in a single-file header-only library

Overview

optional lite: A single-file header-only version of a C++17-like optional, a nullable object for C++98, C++11 and later

Language License Build Status Build status Version download Conan Try it online Try it on godbolt online

Contents

Example usage

#include "nonstd/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 const * 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";
}

Compile and run

prompt>g++ -Wall -Wextra -std=c++03 -I../include -o 01-to_int.exe 01-to_int.cpp && 01-to_int x1
'x1' isn't a number

In a nutshell

optional lite is a single-file header-only library to represent optional (nullable) objects and pass them by value. The library aims to provide a C++17-like optional for use with C++98 and later. If available, std::optional is used. There's also a simpler version, optional bare. Unlike optional lite, optional bare is limited to default-constructible and copyable types.

Features and properties of optional lite are ease of installation (single header), freedom of dependencies other than the standard library and control over object alignment (if needed). optional lite shares the approach to in-place tags with any-lite, expected-lite and with variant-lite and these libraries can be used together.

Not provided are reference-type optionals. optional lite doesn't handle overloaded address of operators.

For more examples, see this answer on StackOverflow [8] and the quick start guide [9] of Boost.Optional (note that its interface differs from optional lite).

License

optional lite is distributed under the Boost Software License.

Dependencies

optional lite has no other dependencies than the C++ standard library.

Installation

optional lite is a single-file header-only library. Put optional.hpp in the include folder directly into the project source tree or somewhere reachable from your project.

Or, if you use the conan package manager, you might follow these steps:

  1. Create source file ./main.cpp, e.g. with the contents of the example code above.

  2. Create ./conanfile.txt file with a reference to variant-lite in the requires section:

    [requires]
    optional-lite/3.2.0  # 3.3.0 when available
    
    [generators]
    cmake
    
  3. Create ./CMakeLists.txt:

    cmake_minimum_required(VERSION 3.1)
    project(optional-example CXX)
    
    include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
    conan_basic_setup()
    
    add_executable(${PROJECT_NAME} main.cpp)
    target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
  4. Run the following commands:

    mkdir build && cd build
    conan install .. --settings arch=x86 --settings compiler=gcc
    cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
    cmake --build . --config Release
    

Synopsis

Contents
Types in namespace nonstd
Interface of optional lite
Algorithms for optional lite
Configuration

Types and values in namespace nonstd

Purpose Type / value Object
To be, or not template< typename T >
class optional;
 
Disengaging struct nullopt_t; nullopt_t nullopt;
Error reporting class bad_optional_access;  
In-place construction struct in_place_tag  
  in_place select type or index for in-place construction
  in_place_type select type for in-place construction
 (variant) in_place_index select index for in-place construction
  nonstd_lite_in_place_type_t( T) macro for alias template in_place_type_t<T>
 (variant) nonstd_lite_in_place_index_t( T ) macro for alias template in_place_index_t<T>

Interface of optional lite

Kind Std Method Result
Construction   optional() noexcept default construct a nulled object
    optional( nullopt_t ) noexcept explicitly construct a nulled object
    optional( optional const & rhs ) move-construct from an other optional
  C++11 optional( optional && rhs ) noexcept(...) move-construct from an other optional
    optional( value_type const & value ) copy-construct from a value
  C++11 optional( value_type && value ) move-construct from a value
  C++11 explicit optional( in_place_type_t<T>, Args&&... args ) in-place-construct type T
  C++11 explicit optional( in_place_type_t<T>, std::initializer_list<U> il, Args&&... args ) in-place-construct type T
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 ) copy-assign from other optional;
destruct current content, if any
  C++11 optional & operator=( optional && rhs ) move-assign from other optional;
destruct current content, if any
  C++11 template< class U, ...>
**optional & operator=( U && v )
move-assign from a value;
destruct current content, if any
  C++11 template< class... Args >
T & emplace( Args&&... args )
emplace type T
  C++11 template< class U, class... Args >
T & emplace( std::initializer_list<U> il, Args&&... args )
emplace type T
Swap   void swap( optional & rhs ) noexcept(...) swap with rhs
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 *() & the current content (const ref);
must contain value
    value_type & operator *() & the current content (non-const ref);
must contain value
  C++11 value_type const & operator *() && the current content (const ref);
must contain value
  C++11 value_type & operator *() && the current content (non-const ref);
must contain value
State   operator bool() const true if content is present
    bool has_value() const true if content is present
    value_type const & value() & 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
  C++11 value_type const & value() && the current content (const ref);
throws bad_optional_access if nulled
  C++11 value_type & value() && the current content (non-const ref);
throws bad_optional_access if nulled
  <C++11 value_type value_or( value_type const & default_value ) const the value, or default_value if nulled
value_type must be copy-constructible
  C++11 value_type value_or( value_type && default_value ) & the value, or default_value if nulled
value_type must be copy-constructible
  C++11 value_type value_or( value_type && default_value ) && the value, or default_value if nulled
value_type must be copy-constructible
Modifiers   void reset() noexcept make empty

Algorithms for optional lite

Kind Std 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 ) noexcept
    template< typename T >
bool operator==( nullopt_t, optional const & x ) noexcept
!=   template< typename T >
bool operator!=( optional const & x, nullopt_t ) noexcept
    template< typename T >
bool operator!=( nullopt_t, optional const & x ) noexcept
<   template< typename T >
bool operator<( optional const &, nullopt_t ) noexcept
    template< typename T >
bool operator<( nullopt_t, optional const & x ) noexcept
<=   template< typename T >
bool operator<=( optional const & x, nullopt_t ) noexcept
    template< typename T >
bool operator<=( nullopt_t, optional const & ) noexcept
>   template< typename T >
bool operator>( optional const & x, nullopt_t ) noexcept
    template< typename T >
bool operator>( nullopt_t, optional const & ) noexcept
>=   template< typename T >
bool operator>=( optional const &, nullopt_t ) noexcept
    template< typename T >
bool operator>=( nullopt_t, optional const & x ) noexcept
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 ) noexcept(...)
create <C++11 template< typename T >
optional<T> make_optional( T const & v )
  C++11 template< class T >
optional< typename std::decay<T>::type > make_optional( T && v )
  C++11 template< class T, class...Args >
optional<T> make_optional( Args&&... args )
  C++11 template< class T, class U, class... Args >
optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
hash C++11 template< class T >
class hash< nonstd::optional<T> >

Configuration

Tweak header

If the compiler supports __has_include(), optional lite supports the tweak header mechanism. Provide your tweak header as nonstd/optional.tweak.hpp in a folder in the include-search-path. In the tweak header, provide definitions as documented below, like #define optional_CPLUSPLUS 201103L.

Standard selection macro

-Doptional_CPLUSPLUS=199711L
Define this macro to override the auto-detection of the supported C++ standard, if your compiler does not set the __cplusplus macro correctly.

Select std::optional or nonstd::optional

At default, optional lite uses std::optional if it is available and lets you use it via namespace nonstd. You can however override this default and explicitly request to use std::optional or optional lite's nonstd::optional as nonstd::optional via the following macros.

-Doptional_CONFIG_SELECT_OPTIONAL=optional_OPTIONAL_DEFAULT
Define this to optional_OPTIONAL_STD to select std::optional as nonstd::optional. Define this to optional_OPTIONAL_NONSTD to select nonstd::optional as nonstd::optional. Default is undefined, which has the same effect as defining to optional_OPTIONAL_DEFAULT.

Disable exceptions

-Doptional_CONFIG_NO_EXCEPTIONS=0 Define this to 1 if you want to compile without exceptions. If not defined, the header tries and detect if exceptions have been disabled (e.g. via -fno-exceptions). Default is undefined.

Macros to control alignment

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_CONFIG_MAX_ALIGN_HACK=0
Define this to 1 to use the max align hack for alignment. Default is 0.

-Doptional_CONFIG_ALIGN_AS=pod-type
Define this to the pod-type you want to align to (no default).

-Doptional_CONFIG_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.

Comparison of std::optional, optional lite and Boost.Optional

optional lite is inspired on std::optional, which in turn is inspired on Boost.Optional. Here are the significant differences.

Aspect std::optional optional lite Boost.Optional
Move semantics yes C++11 no
noexcept yes C++11 no
Hash support yes C++11 no
Throwing value accessor yes yes no
Literal type partially C++11/14 no
In-place construction emplace, tag in_place emplace, tag in_place utility in_place_factory
Disengaged state tag nullopt nullopt none
optional references no 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
  1. is_initialized(), reset(), get().

Reported to work with

The table below mentions the compiler versions optional lite is reported to work with.

OS Compiler Versions
Windows Clang/LLVM ?
  GCC 5.2.0
  Visual C++
(Visual Studio)
8 (2005), 10 (2010), 11 (2012),
12 (2013), 14 (2015), 14 (2017)
GNU/Linux Clang/LLVM 3.5.0, 3.6.0, 7.0.0
  GCC 4.8.4, 5, 6, 8
  ICC 19
macOS Xcode 8.3, 9, 10, 11

Building the tests

To build the tests you need:

The lest test framework is included in the test folder.

The following steps assume that the optional lite source code has been cloned into a directory named c:\optional-lite.

  1. Create a directory for the build outputs for a particular architecture. Here we use c:\optional-lite\build-win-x86-vc10.

     cd c:\optional-lite
     md build-win-x86-vc10
     cd build-win-x86-vc10
    
  2. Configure CMake to use the compiler of your choice (run cmake --help for a list).

     cmake -G "Visual Studio 10 2010" -DOPTIONAL_LITE_OPT_BUILD_TESTS=ON ..
    
  3. Build the test suite in the Debug configuration (alternatively use Release).

     cmake --build . --config Debug
    
  4. Run the test suite.

     ctest -V -C Debug
    

All tests should pass, indicating your platform is supported and you are ready to use optional lite.

Implementation notes

Object allocation and alignment

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 [8, 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:

  1. If the program compiles as C++11 or later, C++11 alignment facilities are used.

  2. If you define -Doptional_CONFIG_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.

  3. If you define -Doptional_CONFIG_ALIGN_AS=pod-type the underlying type is aligned as pod-type. It's your obligation to specify a type with proper alignment.

  4. If you define -Doptional_CONFIG_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.

  5. 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_CONFIG_ALIGN_AS_FALLBACK (default double).

Note that the algorithm of 5. differs from the one Andrei Alexandrescu uses in [8, part 2].

The class template alignment_of<> is gleaned from Boost.TypeTraits, alignment_of [11]. The storage type storage_t<> is adapted from the one I created for spike-expected, expected lite [13].

For more information on constructed unions and alignment, see [8-12].

Other implementations of optional

Notes and references

[1] CppReference. Optional.

[2] ISO/IEC WG21. N4606, section 20.6 Optional objects. July 2016.

[3] Fernando Cacciola, Andrzej Krzemieński. A proposal to add a utility class to represent optional objects (Revision 5).

[4] Andrzej Krzemieński. optional (nullable) objects for C++14. Reference implementation on GitHub.

[5] Simon Brand. P0798R0: Monadic operations for std::optional.

[6] Simon Brand. C++11/14/17 std::optional with functional-style extensions . Reference implementation on GitHub.

[7] Fernando Cacciola. Boost.Optional library.

[8] StackOverflow. How should one use std::optional?. Answer by Timothy Shields. 31 May 2013.

[9] Fernando Cacciola. Boost.Optional Quick start guide.

[10] Andrei Alexandrescu. Generic: Discriminated Unions part 1, part 2, part 3. April 2002.

[11] Herb Sutter. Style Case Study #3: Construction Unions. GotW #85. 2009

[12] Kevin T. Manley. Using Constructed Types in C++ Unions. C/C++ Users Journal, 20(8), August 2002.

[13] StackOverflow. Determining maximum possible alignment in C++.

[14] Boost.TypeTraits, alignment_of ( code ).

[15] Martin Moene. spike-expected (expected-lite.hpp).

Appendix

A.1 Compile-time information

The version of optional lite is available via tag [.version]. The following tags are available for information on the compiler and on the C++ standard library used: [.compiler], [.stdc++], [.stdlanguage] and [.stdlibrary].

A.2 Optional Lite test specification

union: A C++03 union can only contain POD types
optional: Allows to default construct an empty optional (1a)
optional: Allows to explicitly construct a disengaged, empty optional via nullopt (1b)
optional: Allows to default construct an empty optional with a non-default-constructible (1a)
optional: Allows to copy-construct from empty optional (2)
optional: Allows to move-construct from empty optional (C++11, 3)
optional: Allows to copy-construct from empty optional, explicit converting (C++11, 4a)
optional: Allows to copy-construct from empty optional, non-explicit converting (4b)
optional: Allows to move-construct from empty optional, explicit converting (C++11, 5a)
optional: Allows to move-construct from empty optional, non-explicit converting (C++11, 5a)
optional: Allows to copy-construct from non-empty optional (2)
optional: Allows to copy-construct from non-empty optional, explicit converting (C++11, 4a)
optional: Allows to copy-construct from non-empty optional, non-explicit converting (4b)
optional: Allows to move-construct from non-empty optional (C++11, 3)
optional: Allows to move-construct from non-empty optional, explicit converting (C++11, 5a)
optional: Allows to move-construct from non-empty optional, non-explicit converting (C++11, 5b)
optional: Allows to copy-construct from literal value (8)
optional: Allows to copy-construct from literal value, converting (8)
optional: Allows to copy-construct from value (8)
optional: Allows to copy-construct from value, converting (8)
optional: Allows to move-construct from value (C++11, 8b)
optional: Allows to move-construct from value, explicit converting (C++11, 8a)
optional: Allows to move-construct from value, non-explicit converting (C++11, 8b)
optional: Allows to in-place construct from literal value (C++11, 6)
optional: Allows to in-place copy-construct from value (C++11, 6)
optional: Allows to in-place move-construct from value (C++11, 6)
optional: Allows to in-place copy-construct from initializer-list (C++11, 7)
optional: Allows to in-place move-construct from initializer-list (C++11, 7)
optional: Allows to assign nullopt to disengage (1)
optional: Allows to copy-assign from/to engaged and disengaged optionals (2)
optional: Allows to move-assign from/to engaged and disengaged optionals (C++11, 3)
optional: Allows to copy-assign from/to engaged and disengaged optionals, converting, (5)
optional: Allows to move-assign from/to engaged and disengaged optionals, converting (C++11, 6)
optional: Allows to copy-assign from literal value (4)
optional: Allows to copy-assign from value (4)
optional: Allows to move-assign from value (C++11, 4)
optional: Allows to copy-emplace content from arguments (C++11, 7)
optional: Allows to move-emplace content from arguments (C++11, 7)
optional: Allows to copy-emplace content from intializer-list and arguments (C++11, 8)
optional: Allows to move-emplace content from intializer-list and arguments (C++11, 8)
optional: Allows to swap with other optional (member)
optional: Allows to obtain value via operator->()
optional: Allows to obtain moved-value via operator->() (C++11)
optional: Allows to obtain value via operator*()
optional: Allows to obtain moved-value via operator*() (C++11)
optional: Allows to obtain has_value() via operator bool()
optional: Allows to obtain value via value()
optional: Allows to obtain moved-value via value() (C++11)
optional: Allows to obtain value or default via value_or()
optional: Allows to obtain moved-value or moved-default via value_or() (C++11)
optional: Throws bad_optional_access at disengaged access
optional: Throws bad_optional_access with non-empty what()
optional: Allows to reset content
optional: Ensure object is destructed only once (C++11)
optional: Ensure balanced construction-destruction (C++98)
optional: Allows to swaps engage state and values (non-member)
optional: Provides relational operators (non-member)
optional: Provides mixed-type relational operators (non-member)
make_optional: Allows to copy-construct optional
make_optional: Allows to move-construct optional (C++11)
make_optional: Allows to in-place copy-construct optional from arguments (C++11)
make_optional: Allows to in-place move-construct optional from arguments (C++11)
make_optional: Allows to in-place copy-construct optional from initializer-list and arguments (C++11)
make_optional: Allows to in-place move-construct optional from initializer-list and arguments (C++11)
std::hash<>: Allows to obtain hash (C++11)
tweak header: reads tweak header if supported [tweak]
Issues
  • Fix errors detected by clang with -Werror

    Fix errors detected by clang with -Werror

    I tried to use optional-lite in our project and receive some errors when compiling by clang with -Werror flag. I've tested it on FreeBSD with clang 3.4.1 and on Win10 with clang 6.0.0.

    This PR contains fixes for errors detected by clang.

    opened by eao197 10
  • error: explicit specialization of non-template class 'hash'

    error: explicit specialization of non-template class 'hash'

    I get this error when building the tests on macOS:

    In file included from test/optional-lite.t.cpp:7: In file included from test/optional-lite.t.h:12: include/nonstd/optional.hpp:1070:7: error: explicit specialization of non-template class 'hash' class hash< nonstd::optional > ^ ~~~~~~~~~~~~~~~~~~~~~~~ 1 error generated.

    My Clang version:

    $ clang --version
    Apple LLVM version 8.1.0 (clang-802.0.42)
    Target: x86_64-apple-darwin16.5.0
    Thread model: posix
    InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
    

    My compiler flags:

    -std=c++11
    
    opened by njlr 8
  • gdb pretty printer

    gdb pretty printer

    for debugging optional-lite I propose this pretty printer

    class NonStdOptionalPrinter(SingleObjContainerPrinter):
        "Print a nonstd::optional"
    
        def __init__ (self, typename, val):
            alternatives = get_template_arg_list(val.type)
            valtype = self._recognize (val.type.template_argument(0))
            self.typename = strip_versioned_namespace(typename)
            self.typename = re.sub('^nonstd::(optional_lite::|)(optional::|)(.*)', 
                                                  r'nonstd::\1\3<%s>' % valtype, 
                                                  self.typename, 1)
            self.val = val
            self.contained_type = alternatives[0]
            addr = val['contained']['data']['__data'].address
            contained_value = addr.cast(self.contained_type.pointer()).dereference()
            visualizer = gdb.default_visualizer (contained_value)
            super (NonStdOptionalPrinter, self).__init__ (contained_value, visualizer)
    
        def to_string (self):
            if self.contained_value is None:
                return "%s [no contained value]" % self.typename
            if self.visualizer:
                return "%s containing %s" % (self.typename,
                                             self.visualizer.to_string())
            return self.typename
    

    And don't forget add printer with this code

    libstdcxx_printer.add_version('nonstd::optional_lite::',
                                      'optional', NonStdOptionalPrinter)
    
    opened by bas524 7
  • Using `value_or()` changes stored value

    Using `value_or()` changes stored value

    Code:

    #include <https://raw.githubusercontent.com/martinmoene/optional-lite/master/include/nonstd/optional.hpp>
    #include <iostream>
    #include <string>
    
    int main()
    {
        nonstd::optional<std::string> s;
        s = "test";
        std::cout << (*s == "test") << std::endl;
        std::cout << (s.value_or("") == "test") << std::endl; // comment this line
        std::cout << (s->empty()) <<  std::endl;
    }
    

    Output: 1 1 1

    Expected output: 1 1 0

    If I comment line with value_or it works just fine. GCC version also works as expected, but clang and msvc does not.

    Live code: https://godbolt.org/z/frqjfr

    opened by deadem 6
  • README

    README "rhs"

    https://github.com/martinmoene/optional-lite#dependencies

    This section says "rhs dependencies" where it should probably be "other dependencies".

    opened by TartanLlama 6
  • Conan package

    Conan package

    I was going to use this library in next version of https://github.com/agauniyal/rang for which I was going to use conan.io for package management. Thought instead of bundling or using git submodule, why not publish optional-lite on conan as well - https://bintray.com/agauniyal/rang/optional-lite%3Arang

    Since its a header only library its not much of maintenance task so I'll be happy to maintain this. You can mention in readme if you want or if you have any objection to this upload please leave a comment :) The repo for conan recipie is - https://github.com/agauniyal/conan-optional-lite

    enhancement 
    opened by agauniyal 6
  • Enhance in_place construction

    Enhance in_place construction

    The current implementation required ad least a move-constructor for in-place construction. This made it impossible to directly, create an optional of a type without copy and move operators.

    A workaround is using the variadic emplace function, but it requires to construct the object in two steps.

    std::optional does not require any copy or move operation for in-place construction

    opened by fekir 5
  • optional_HAVE_INITIALIZER_LIST is undefined

    optional_HAVE_INITIALIZER_LIST is undefined

    The class declares initialize_list functions under a optional_CPP11_OR_GREATER preprocessor block but the header is in a optional_HAVE_INITIALIZER_LIST block.

    We should either:

    1. Change the #include to be wrapped by #if optional_CPP11_OR_GREATER
    2. Change the declarations of the initializer_list functions to be wrapped in optional_HAVE_INITIALIZER_LIST and add a define for optional_HAVE_INITIALIZER_LIST

    I suspect 2 is wanted.

    opened by mattyclarkson 5
  • Compile error on implicit construction of T from another type

    Compile error on implicit construction of T from another type

    Snippet to reproduce:

    // g++ -std=c++14 -o x x.cpp
    
    #include "optional.hpp"
    
    class A
    {
    };
    
    // B is implicitly constructible from A.
    class B
    {
    public:
      B(A a)
      {
      }
    };
    
    // f accepts optional<B>.
    void f(nonstd::optional<B> b)
    {
    }
    
    // check conditions on https://en.cppreference.com/w/cpp/utility/optional/optional item 8
    static_assert(std::is_constructible<B, A&&>::value, "");
    static_assert(!std::is_same<std::decay_t<A&&>, nonstd::in_place_t>::value, "");
    static_assert(!std::is_same<std::decay_t<A&&>, nonstd::optional<B>>::value, "");
    
    int main()
    {
      A a;
    
      f(a); // Call f with A, compile error.
    }
    

    This snippet fails to compile on gcc 5.4 in C++14 mode:

    $ g++ -std=c++14 -o x x.cpp
    x.cpp: In function ‘int main()’:
    x.cpp:31:6: error: could not convert ‘a’ from ‘A’ to ‘nonstd::optional_lite::optional<B>’
       f(a);
          ^
    

    It works on gcc 8.2 in C++17 mode: https://godbolt.org/z/2XyZum

    opened by yoursunny 5
  •  mingw 4.8 compilation error

    mingw 4.8 compilation error

    I know that your library is reported to work on mingw52

    on mingw 4.8 ,__cplusplus = 201103 but it seem like REF_QUALIFIER feature is not supported

    this naive patch fixed compilation error for me for optional-lite version 3.1.1

    Index: optional.hpp
    ===================================================================
    --- optional.hpp	(version 3.1.1)
    +++ optional.hpp	(fix have ref)
    @@ -254,6 +254,7 @@
     # define optional_COMPILER_GNUC_VERSION   0
     #endif
     
    +
     #if defined(__clang__)
     # define optional_COMPILER_CLANG_VERSION  optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
     #else
    @@ -345,7 +346,7 @@
     # define optional_nullptr  NULL
     #endif
     
    -#if optional_HAVE( REF_QUALIFIER )
    +#if optional_HAVE( REF_QUALIFIER )  &&  ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 )
     # define optional_ref_qual  &
     # define optional_refref_qual  &&
     #else
    @@ -718,7 +719,7 @@
         {
             return as<value_type>();
         }
    -
    +#if optional_HAVE( REF_QUALIFIER )  &&  ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 )
         value_type const & value() const optional_ref_qual
         {
             return * value_ptr();
    @@ -742,7 +743,18 @@
         }
     
     #endif
    +#else
    +    value_type const & value() const
    +    {
    +        return * value_ptr();
    +    }
     
    +    value_type & value()
    +    {
    +        return * value_ptr();
    +    }
    +#endif
    +
     #if optional_CPP11_OR_GREATER
     
         using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type;
    
    

    best regards.

    opened by davidtazy 4
  • compile with icc 19

    compile with icc 19

    https://github.com/martinmoene/optional-lite/blob/ed68dc81d8e4fbe7ece18ed8f1e3111d6258d895/include/nonstd/optional.hpp#L1250 assumes that std17::is_nothrow_swappable::value exists, but for a pre-c++-17 compiler it is not defined in that template class: https://github.com/martinmoene/optional-lite/blob/ed68dc81d8e4fbe7ece18ed8f1e3111d6258d895/include/nonstd/optional.hpp#L459. The latest Intecl compiler (icpc 19) observes this, and refuses to compile the code.

    Can we add the appropriate value field?

    opened by mabraham 4
  • Support for

    Support for "bits/type_traits.h"

    I am cross-compiling for ARM architecture with arm-linux-g++ (GCC) 3.4.4 compiler and the standard library header type_traits is under bits folder. To fix the related compilation issue I have defined the following preprocessor directives, but I think that there is a better way to do the same thing.

    #define optional_HAVE_BITS_TYPE_TRAITS  defined(__arm__)
    
    #if optional_HAVE( BITS_TYPE_TRAITS )
    # include <bits/type_traits.h>
    #elif optional_HAVE( TYPE_TRAITS )
    # include <type_traits>
    #elif optional_HAVE( TR1_TYPE_TRAITS )
    # include <tr1/type_traits>
    #endif
    
    opened by davalv 1
  • Invalid copy/move constructible/assignable detection

    Invalid copy/move constructible/assignable detection

    Code:

    #include <https://raw.githubusercontent.com/martinmoene/optional-lite/master/include/nonstd/optional.hpp>
    #include <iostream>
    #include <string>
    
    struct A
    {
        A() = default;
        A(const A &) = delete;
        A& operator=(const A &) = delete;
        A(A &&) = delete;
        A& operator=(A &&) = delete;
    };
    
    int main()
    {
        std::cout << "Copy constructible: "
            << std::is_copy_constructible<A>::value << " "
            << std::is_copy_constructible<nonstd::optional<A>>::value
            << std::endl;
    
        std::cout << "Move constructible: "
            << std::is_move_constructible<A>::value << " "
            << std::is_move_constructible<nonstd::optional<A>>::value
            << std::endl;
    
        std::cout << "Copy assignable: "
            << std::is_copy_assignable<A>::value << " "
            << std::is_copy_assignable<nonstd::optional<A>>::value
            << std::endl;
    
        std::cout << "Move assignable: "
            << std::is_move_assignable<A>::value << " "
            << std::is_move_assignable<nonstd::optional<A>>::value
            << std::endl;
    }
    

    Output:

    Copy constructible: 0 1
    Move constructible: 0 1
    Copy assignable: 0 1
    Move assignable: 0 1
    

    Expected output:

    Copy constructible: 0 0
    Move constructible: 0 0
    Copy assignable: 0 0
    Move assignable: 0 0
    

    Live demo: https://godbolt.org/z/a7fhv3

    opened by deadem 1
  • Incorrect detection of std::in_place

    Incorrect detection of std::in_place

    optional.hpp seems to rely only on the C++ standard version in use to choose between the std::in_place facility from the standard library or its own implementation.

    https://github.com/martinmoene/optional-lite/blob/86db12f3b6c2026ad83efd51c5ce3622bb06f1b8/include/nonstd/optional.hpp#L88-L99

    However, simply compiling in C++17 mode doesn't guarantee that the standard library contains these facilities. For instance, this detection technique fails on Ubuntu 16.04 when compiling with clang-5.0 (and the default libstdc++):

    $ clang++-5.0 -xc++ -std=c++17 -ferror-limit=5 -c -o /dev/null - <<< '#include "optional.hpp"'
    In file included from <stdin>:1:
    ./optional.hpp:94:12: error: no member named 'in_place' in namespace 'std'
    using std::in_place;
          ~~~~~^
    ./optional.hpp:95:12: error: no member named 'in_place_type' in namespace 'std'
    using std::in_place_type;
          ~~~~~^
    ./optional.hpp:96:12: error: no member named 'in_place_index' in namespace 'std'
    using std::in_place_index;
          ~~~~~^
    ./optional.hpp:97:12: error: no member named 'in_place_t' in namespace 'std'
    using std::in_place_t;
          ~~~~~^
    ./optional.hpp:98:12: error: no member named 'in_place_type_t' in namespace 'std'
    using std::in_place_type_t;
          ~~~~~^
    fatal error: too many errors emitted, stopping now [-ferror-limit=]
    6 errors generated.
    
    opened by Pesa 0
  • nonstd::optional is not a literal type

    nonstd::optional is not a literal type

    I am looking for C++14 optional drop-in which I can use in constexpr contexts. From the Readme it seems to fit my needs, because you state this implementation provides a LiteralType in that case. I tried to compile

    int main()
    {
      constexpr nonstd::optional<int> o = 2;
    }
    

    with std=c++14 two different compilers (gcc-8 and clang-5) and both failed to compile the code.

    While trying to fix the issue with custom patches I encountered following problems:

    To make the type satisfy std::is_literal_type (deprecated, I know)

    • I had to make the destructor of optional trivial for trivially destructible types T. This can be achieved by inheriting from a base class and using a template specialization.
    • I had to mark at least on constructor of storage constexpr

    To make the type usuable in constexpr contexts:

    • placement new in storage_t is not constexpr, so nonstd::optional with this storage implementation is not going to be usable in constexpr contexts.

    Did i misunderstand something terribly wrong and/or do you think it would be worthwhile to provide some patches to target the above points.

    opened by maikel 6
Releases(v3.5.0)
  • v3.5.0(Sep 19, 2021)

    This release of optional lite contains the following changes:

    Additions:

    • Add script tc-cl.bat (nonstd-lite-project issues 54).
    • Add macro optional_static_assert() and compile-time checks on T.
    • Add PlatformIO library manifest file library.json (replaces #64, thanks to @Nullfati).
    • Add export() to CMakeLists.txt enabling importing targets. See nonstd-lite-project issues 50.

    Changes:

    • Enhance in-place construction (#66, thanks @@fekir).
    • Change to use #if defined(_MSC_VER) to avoid -Wundef warning (#65, thanks @eepp).
    • Change usage of =default with test structures to VS2015 for (#61).
    • Handle lest test framework as system include to prevent warnings.

    Fixes:

    • Fix value_or() from changing stored value (issue #60, thanks @deadem, @mortenfyhn and @phprus).
    Source code(tar.gz)
    Source code(zip)
    optional.hpp(53.41 KB)
  • v3.4.0(Nov 22, 2020)

  • v3.3.0(Nov 11, 2020)

    Release 3.3.0 of optional lite contains the following changes.

    Additions:

    • Add tweak header support

    Changes:

    • Add .editorconfig.
    • Add TortoiseGit integration with GitHub issues.
    • Add build folder and IDE folders/files to .gitignore (.vs, .vscode, CodeBlocks).
    • Change vcpkg install to use CMake
    • Change badge 'on conan' to refer to conan-center (thanks @jgsogo).
    • Improve section on Conan in Readme.
    • Remove no longer used struct enabler.
    • Special-case usage of ref qualifiers for GNUC 4.8 (#56,thanks to @davidtazy).
    • Update list of known good compilers (Xcode) (#54, thanks to @past-due).
    • Add settings options to conanfile (#46, thanks to @ngrodzitski).
    • Add Visual Studio 2019 to the Appveyor build matrix, nonstd lite project issue 47.
    • Add badge 'on godbolt', nonstd-lite-project issue 36.
    • Improve MSVC version table, nonstd-lite-project issue 38.

    Fixes:

    • Handle presence of various C++11 type traits (#58, thanks to @trapexit)
    • Change requires() to use a default template argument (#55, #57, thanks to @improbablejan), see nonstd-lite-project issue 40
    • Fix optional_HAVE_INITIALIZER_LIST is undefined #51 (#52)
    • Fix compilation with exceptions disabled. (#47, #49, thanks to @viettrungluu)
    • Fix compilation of examples by adding CMakeLists.txt (#48, #50, thanks to @viettrungluu)
    Source code(tar.gz)
    Source code(zip)
    optional.hpp(52.12 KB)
  • v3.2.0(Apr 25, 2019)

  • v3.1.1(Oct 2, 2018)

  • v3.1.0(Oct 2, 2018)

    To be written

    • optional_CPLUSPLUS
    • Add CMake installation target (inspired on PR #30)
    • Use other and value as parameter names; fix in-place type for make_optional()
    • Mention expected-lite
    • Make use of __has_include() more robust
    • Update shared in_place facility
    • Add CMake options to select between std::optional and nonstd::optional
    • Add -Wsign-onversion
    • Handle AppleClang C++17 compiler flag
    • Correct comment
    • Prevent -Wunused-function warning (inspired on PR #29)
    • Prevent -Wconversion message (inspired on PR #27)
    • Add -Wconversion warning
    • Rename to optional_REQUIRES_A() SFINAE on
    • .._A(): method argument type
    • .._T(): template argument type
    • .._R(): return type
    • Refine require clauses
    • Add converting construction, assignment (issue #27)
    • Add version to CMakeLists.txt
    • Add script to update version
    • Obviate need for -DNOMINMAX with MSVC (nonstd-lite issue 16)
    • Fix detection of GNUC, update style for if defined()
    • Expand Travis configuration
    • Update lest to version 1.33.2 (issue #26)
    • Change whitespace
    • Getting rid of conversion from ‘long unsigned int’ to ‘unsigned int' may change value-messages (#25)
    • Getting rid of conversion from ‘long unsigned int’ to ‘unsigned int' may change value-messages
    • Update optional.hpp
    • Make some rvalue qualified function to reuse lvalue versions of corresponding functions. (#21)Thanks @ngrodzitski
    • Let C++ standard be specified manually via optional_CPLUSPLUS, issue #20
    • Fix web links in section Notes and References
    • Fix to not require empty optional for emplace
    • Fix issue #18 (thanks to @rwst Ralf Stephan)
    • Add test for issue #18
    • Use CMAKE_CXX_STANDARD, remove c++03 target
    • Add "LANGUAGES CXX" to project
    • Declare stream operator before inclusion of lest test framework
    • Align CMake configuration (add_library)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(Jun 4, 2018)

    optional lite has been re-licensed under the Boost Software License (BSL) (issue #17).

    Additions

    • Made v2.3.0 available in conan (thanks to @agauniyal).

    Changes

    • Enabled differentiating between MSVC 14.0 (VS2015) and 14.1 (VS2017).
    • Expanded Travis and Appveyor configurations.
    • Renamed optional-lite to optional-main.
    • Suppressed -Wundef for optional.hpp.
    • Updated lest to version 1.33.1.

    Fixes

    • Added missing using std::nullopt_t for C++17 std::optional
    • Corrected rhs to other (issue #12, thanks to @TartanLlama)
    Source code(tar.gz)
    Source code(zip)
    optional.hpp(29.77 KB)
  • v2.3.0(Dec 10, 2017)

    This release of optional lite contains the following changes.

    Changes

    This release lets nonstd::optional use std::optional if it's available. Further in_place_type and in_place_index were added. The readme now has Conan installation instructions and badge (issue #9, thanks to @agauniyal) as well as a section Other implementations of optional.

    Fixes

    None.

    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(Nov 17, 2017)

    This release of optional lite contains the following changes.

    Changes Relational operators now support mixed value types as specified in C++17 and are constexpr.

    Fixes The struct/class mismatch for std::hash has been fixed (thanks to Łukasz A.J. Wrona @LAJW).

    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Jul 11, 2017)

    This release of optional lite contains the following changes.

    Additions Tests and examples can now also be build via buck (thanks to Nick La Rooy @njlr). A try it online badge has been added to the Readme.

    Fixes Issue #5 has been fixed by providing std::swap() via header file <functional>. Compiler selection in test/CMakeLists.txt file has been fixed.

    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Nov 5, 2016)

  • v1.0.3(Nov 2, 2016)

    This release fixes method value_or() to be const, organizes the files like with any-lite and variant-lite and updates lest_cpp03.hpp to version 1.27.0.

    Further, optional lite now uses the MIT lisence.

    Note: this is the last release that supports Visual C++ 6 (VC6, VS6).

    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 for use with C++98 and later and Visual C++ 6 (VC6).

    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Apr 14, 2015)

    This release fixes the declaration of nullopt and updates lest_cpp03.hpp to version 1.22.0.

    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 for use with C++98 and later and Visual C++ 6 (VC6).

    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Jan 5, 2015)

    This release contains several small changes and corrections.

    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 for use with C++98 and later and Visual C++ 6 (VC6).

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Dec 21, 2014)

    This is the initial release of optional lite.

    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 for use with C++98 and later and Visual C++ 6 (VC6).

    Source code(tar.gz)
    Source code(zip)
Owner
Martin Moene
C++ programmer at Universiteit Leiden, member and former webeditor of @accu-org.
Martin Moene
string_view lite - A C++17-like string_view for C++98, C++11 and later in a single-file header-only library

string_view lite: A single-file header-only version of a C++17-like string_view for C++98, C++11 and later Contents Example usage In a nutshell Licens

Martin Moene 321 Jun 22, 2022
variant lite - A C++17-like variant, a type-safe union for C++98, C++11 and later in a single-file header-only library

variant lite: A single-file header-only version of a C++17-like variant, a type-safe union for C++98, C++11 and later Contents Example usage In a nuts

Martin Moene 208 Jun 9, 2022
expected lite - Expected objects in C++11 and later in a single-file header-only library

expected lite: expected objects for C++11 and later expected lite is a single-file header-only library for objects that either represent a valid value

Martin Moene 216 Jun 18, 2022
gsl-lite – A single-file header-only version of ISO C++ Guidelines Support Library (GSL) for C++98, C++11, and later

gsl-lite: Guidelines Support Library for C++98, C++11 up metadata build packages try online gsl-lite is an implementation of the C++ Core Guidelines S

gsl-lite 741 Jun 27, 2022
gsl-lite – A single-file header-only version of ISO C++ Guidelines Support Library (GSL) for C++98, C++11, and later

gsl-lite: Guidelines Support Library for C++98, C++11 up metadata build packages try online gsl-lite is an implementation of the C++ Core Guidelines S

gsl-lite 741 Jun 27, 2022
Single-header header-only C++11 / C++14 / C++17 library for easily managing set of auto-generated type-safe flags.

Single-header header-only C++11 / C++14 / C++17 library for easily managing set of auto-generated type-safe flags. Quick start #include <bitflags/bitf

Marin Peko 69 May 4, 2022
Libft is an individual project at 42 that requires us to re-create some standard C library functions including some additional ones that can be used later to build a library of useful functions for the rest of the program.

?? Index What is Libft? List of Functions Technologies ✨ What is Libft? Libft is an individual project at 42 that requires us to re-create some standa

Paulo Rafael Ramalho 7 Jan 17, 2022
A collection of std-like single-header C++ libraries

itlib: iboB's Template Libraries A collection of small single-header C++ libraries similar to or extending the C++ standard library. See below for a l

Borislav Stanimirov 72 Jun 20, 2022
A header-only, unobtrusive, almighty alternative to the C++ switch statement that looks just like the original.

uberswitch A header-only, unobtrusive, almighty alternative to the C++ switch statement that looks just like the original. Sample usage (incomplete -

Fabio 76 Jun 20, 2022
C++11/14/17 std::optional with functional-style extensions and reference support

optional Single header implementation of std::optional with functional-style extensions and support for references. Clang + GCC: MSVC: std::optional i

Sy Brand 643 Jun 21, 2022
A standard conforming C++20 implementation of std::optional.

A standard conforming C++20 implementation of std::optional.

null 29 Feb 11, 2022
Monadic interface for std::optional

optional Simple monadic interface for std::optional Installation Just copy and include optional.h header in your project Usage All operations are in b

null 8 Apr 15, 2022
Named Optional Arguments in C++17

Optional Argument in C++ News Mon 02 Dec 2019 [0.0.2 tag] Cancel any possible implicit conversion by making constructors explicit. Thu 21 Nov 2019 [0.

pixor 8 Dec 2, 2019
jkds is a modern header-only C++20 library that complements the standard library.

jkds is a modern header-only C++20 library that complements the standard library. It provides generic atypical data structures, ergonomic functional programming abstractions, and then some.

Alberto Schiabel 5 May 24, 2022
Bsl - Rust 2018 and C++20, "constexpr everything", AUTOSAR compliant header-only library intended to support the development of critical systems applications

Description The Bareflank Support Library (BSL) is a Rust 2018 and C++20, "constexpr everything", AUTOSAR compliant header-only library intended to su

Bareflank 63 Jun 18, 2022
Modern C++ generic header-only template library.

nytl A lightweight and generic header-only template library for C++17. Includes various utility of all kind that i needed across multiple projects: Ex

Jan 93 Jun 20, 2022
Lightweight single-file utilities for C99. Portable & zero dependency

plainlibs Lightweight single-file utilities for C99. Key Features Portable across Unix & Windows (including MSVC) Zero dependencies (besides C stdlib)

null 2 Jun 19, 2022
Library that simplify to find header for class from STL library.

Library that simplify to find header for class from STL library. Instead of searching header for some class you can just include header with the class name.

null 6 Jun 7, 2022
Improved and configurable drop-in replacement to std::function that supports move only types, multiple overloads and more

fu2::function an improved drop-in replacement to std::function Provides improved implementations of std::function: copyable fu2::function move-only fu

Denis Blank 391 Jun 18, 2022