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.

Documentation Status Clang + GCC: Linux Build Status MSVC: Windows Build Status

std::optional is the preferred way to represent an object which may or may not have a value. Unfortunately, chaining together many computations which may or may not produce a value can be verbose, as empty-checking code will be mixed in with the actual programming logic. This implementation provides a number of utilities to make coding with optional cleaner.

For example, instead of writing this code:

std::optional<image> get_cute_cat (const image& img) {
    auto cropped = crop_to_cat(img);
    if (!cropped) {
      return std::nullopt;
    }

    auto with_tie = add_bow_tie(*cropped);
    if (!with_tie) {
      return std::nullopt;
    }

    auto with_sparkles = make_eyes_sparkle(*with_tie);
    if (!with_sparkles) {
      return std::nullopt;
    }

    return add_rainbow(make_smaller(*with_sparkles));
}

You can do this:

tl::optional<image> get_cute_cat (const image& img) {
    return crop_to_cat(img)
           .and_then(add_bow_tie)
           .and_then(make_eyes_sparkle)
           .map(make_smaller)
           .map(add_rainbow);
}

The interface is the same as std::optional, but the following member functions are also defined. Explicit types are for clarity.

  • map: carries out some operation on the stored object if there is one.
    • tl::optional<std::size_t> s = opt_string.map(&std::string::size);
  • and_then: like map, but for operations which return a tl::optional.
    • tl::optional<int> stoi (const std::string& s);
    • tl::optional<int> i = opt_string.and_then(stoi);
  • or_else: calls some function if there is no value stored.
    • opt.or_else([] { throw std::runtime_error{"oh no"}; });
  • map_or: carries out a map if there is a value, otherwise returns a default value.
    • tl::optional<std::size_t> s = opt_string.map_or(&std::string::size, 0);
  • map_or_else: carries out a map if there is a value, otherwise returns the result of a given default function.
    • std::size_t get_default();
    • tl::optional<std::size_t> s = opt_string.map_or_else(&std::string::size, get_default);
  • conjunction: returns the argument if a value is stored in the optional, otherwise an empty optional.
    • tl::make_optional(42).conjunction(13); //13
    • tl::optional<int>{}.conjunction(13); //empty
  • disjunction: returns the argument if the optional is empty, otherwise the current value.
    • tl::make_optional(42).disjunction(13); //42
    • tl::optional<int>{}.disjunction(13); //13
  • take: returns the current value, leaving the optional empty.
    • opt_string.take().map(&std::string::size); //opt_string now empty;

In addition to those member functions, optional references are also supported:

int i = 42;
tl::optional<int&> o = i;
*o == 42; //true
i = 12;
*o == 12; //true
&*o == &i; //true

Assignment has rebind semantics rather than assign-through semantics:

int j = 8;
o = j;

&*o == &j; //true

Compiler support

Tested on:

  • Linux
    • clang 6.0.1
    • clang 5.0.2
    • clang 4.0.1
    • clang 3.9
    • clang 3.8
    • clang 3.7
    • clang 3.6
    • clang 3.5
    • g++ 8.0.1
    • g++ 7.3
    • g++ 6.4
    • g++ 5.5
    • g++ 4.9
    • g++ 4.8
  • Windows
    • MSVC 2015
    • MSVC 2017

Standards Proposal

This library also serves as an implementation of WG21 standards paper P0798R0: Monadic operations for std::optional. This paper proposes adding map, and_then, and or_else to std::optional.


CC0

To the extent possible under law, Sy Brand has waived all copyright and related or neighboring rights to the optional library. This work is published from: United Kingdom.

Comments
  • Return type not correctly deduced

    Return type not correctly deduced

    Consider this code:

    tl::optional<int> op = 42;
        op.map([](auto i) {
            if (i == 42)
            {
                return tl::make_optional("good");
            }
            return tl::nullopt;
        });
    

    This won't compile. The error message is: auto' in return type deduced as 'utils::nullopt_t' here but deduced as 'utils::optional<const char *>' in earlier return statement Should't tl::nullopt be a value of typetl::optional<> for all contained types?

  • Added explicit default initialization in copy constructor

    Added explicit default initialization in copy constructor

    Copy constructor produces warnings, thus failing the build with -Werror=all. Added explicit initialization.

    ../3rdparty/optional/include/tl/optional.hpp:455:3: error: base class 'struct tl::detail::optional_operations_base<std::__cxx11::basic_string<char> >' should be explicitly initialized in the copy constructor [-Werror=extra]
      455 |   optional_copy_base(const optional_copy_base &rhs) {
          |   ^~~~~~~~~~~~~~~~~~
    cc1plus: all warnings being treated as errors
    
  • Conflicting implementations of map_imp in optional.hpp and expected.hpp

    Conflicting implementations of map_imp in optional.hpp and expected.hpp

    Hey,

    I am using both your implementation for optional and expected in the same project, and I got compile issues when including both in the same file and using map on either of them:

    // Minimal code to expose this:
    #include "expected.hpp"
    #include "optional.hpp"
    
    void MyFunction()
    {
        tl::optional<int> my_optional;
        my_optional.map([](int value) { return value + 1; });
    }
    

    Compilation failure:

    optional.h: In instantiation of 'constexpr auto tl::optional<T>::map(F&&) & [with F = MyFunction()::<lambda(int)>; T = int]':
    file.cc:14:56:   required from here
    optional.h:770:20: error: call of overloaded 'map_impl(tl::optional<int>&, MyFunction()::<lambda(int)>)' is ambiguous
         return map_impl(*this, std::forward<F>(f));
                ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    The problem is that both optional and expected use a helper called map_impl, but with different implementations.

    A simple solution I applied is simply renaming map_impl to optional_map_impl and expected_map_impl, respectively.

    Jeroen

    PS Thanks a lot for these libraries, I love them :)

  • CMake generation fails for Release build with tests on and documentation off

    CMake generation fails for Release build with tests on and documentation off

    I'm building the package on Devuan ASCII (= Debian Stretch without systemd), with CMake 3.13.1 under /usr/local/src, locally built from a source tarball.

    I've done the following:

    • clone the repo to /path/to/tl-optional
    • cd /path/to/tl-optional
    • ccmake .
    • Set build type to Release (I realize that shouldn't matter much)
    • Set documentation to OFF
    • Configure again
    • Generate

    and I get:

     CMake Error at CMakeLists.txt:34 (add_executable):
       Cannot find source file:
    
         /path/to/tl-optional/tests/main.cpp
    
       Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
       .hpp .hxx .in .txx
    
    
     CMake Error: Cannot determine link language for target "tests".
     CMake Error: CMake can not determine linker language for target: tests
    
  • Self-assignment not handled properly

    Self-assignment not handled properly

    Hi,

    It seems that the assignment operator of optional<T> does not handle self-assignment properly, which can cause fatal errors (my application crashes because of that). IMHO self-assignment must always be safe and should actually do nothing.

    I checked it with following test:

    struct fail_on_copy_self {
        int value;
        fail_on_copy_self(int v) : value(v) {}
        fail_on_copy_self(const fail_on_copy_self& other) {
            REQUIRE(&other != this);
        }
    };
    
    TEST_CASE("Assignment to self", "[assignment.self]") {
        tl::optional<fail_on_copy_self> o = fail_on_copy_self(42);
    
        o = o;
        REQUIRE(o->value == 42);
    }
    

    Output:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    tests is a Catch v2.0.1 host application.
    Run with -? for options
    
    -------------------------------------------------------------------------------
    Assignment to self
    -------------------------------------------------------------------------------
    assignment.cpp:81
    ...............................................................................
    
    assignment.cpp:77: FAILED:
      REQUIRE( &other != this )
    with expansion:
      0x00007fff63b977f0 != 0x00007fff63b977f0
    
    terminate called after throwing an instance of 'Catch::TestFailureException'
    assignment.cpp:81: FAILED:
      {Unknown expression after the reported line}
    due to a fatal error condition:
      SIGABRT - Abort (abnormal termination) signal
    
    ===============================================================================
    test cases:  12 |  11 passed | 1 failed
    assertions: 326 | 324 passed | 2 failed
    
    Abgebrochen
    

    As you can see, the copy constructor of type T is called with &other == this, which seems very strange. That's not intended, is it? ;)

  • Current master is broken (cmake error)

    Current master is broken (cmake error)

    Even when running Travis-CI/AppVeyor on the current master branch, they fail with the following error:

    $ mkdir build && cd build && cmake -DCXXSTD=$CXXSTD .. && make && ./tests
    -- The CXX compiler identification is GNU 5.5.0
    -- Check for working CXX compiler: /usr/bin/g++-5
    -- Check for working CXX compiler: /usr/bin/g++-5 -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    CMake Error at build/_deps/tl_cmake-src/add-tl.cmake:6 (target_sources):
      target_sources may only set INTERFACE properties on INTERFACE targets
    Call Stack (most recent call first):
      CMakeLists.txt:19 (tl_add_library)
    -- Configuring incomplete, errors occurred!
    

    Since the same revision passed CI 5 days ago, I suspect it has to do with a change in the tl-cmake repository 4 days ago. I have no idea how this CMake stuff works exactly, but in the CMakeLists.txt I see a dependency to https://github.com/TartanLlama/tl-cmake.git without specifying an exact revision. This is generally a very bad idea since it's impossible to get stable, reproducible builds.

    So I would suggest to link to a specific revision (tag or commit SHA). Or even better, remove the dependency completely :wink:

    #31 is currently blocked by this issue since CI always fails.

  • Align with proposal

    Align with proposal

    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0798r4.html#transform-with-void-returning-functions

    Rename map to transform Remove capability for mapping void-returning functions

  • Suggestion: `take()` should always move

    Suggestion: `take()` should always move

    Hello, thank you for this library! It does make optional much more pleasant to use.

    Since take() will always empty the optional it is invoked upon, I expected it to always move. However, I noticed that there are const and non-const / lvalue and rvalue overloads for this function, and only the non-const-rvalue one will move. Is there a particular reason for this? The const overloads are not usable anyway, as reset() is non-const.

    I suggest replacing all overloads with:

      optional take() {
        optional ret = std::move(*this);
        reset();
        return ret;
      }
    

    A moving take() can be helpful when using optionals of move-only types, for example

    tl::optional<some_move_only_t> opt = ...;
    // ...
    some_move_only_t value = opt.take().value();
    

    is a bit neater to me than:

    tl::optional<some_move_only_t> opt = ...;
    // ...
    some_move_only_t value = std::move(opt).value();
    

    Especially since the latter leaves the optional non-empty, but with a moved-from value. Right now, to get the same effect, you would have to do like so:

    tl::optional<some_move_only_t> opt = ...;
    // ...
    some_move_only_t value = std::move(opt).take().value();
    

    Which is a bit noisy.

    Also, perhaps there is some merit to having a take_value() member function that is semantically equivalent to take().value() but avoids constructing a temporary optional -- what do you think?

  • Add syntax highlighting to readme

    Add syntax highlighting to readme

    Hi, this repo was mentioned at NDC TechTown and while looking into it I noticed that the code examples in the readme are colorless, so I added syntax highlighting in case you want it.

  • Compile error with Clang 3.4

    Compile error with Clang 3.4

    Hi, thanks for this nice library!

    Unfortunately it doesn't compile with Clang 3.4 (which is shipped with Ubuntu Trusty, and thus also installed on Travis-CI). I see in your readme that you tested with Clang >= 3.5. Would it be hard to add support for Clang 3.4?

    Following compile errors occur:

    $ clang++ -std=c++11 optional.hpp
    
    ../libs/optional/tl/optional.hpp:388:27: error: no member named 'is_trivially_copy_constructible' in namespace 'std'
    template <class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ../libs/optional/tl/optional.hpp:60:8: note: expanded from macro 'TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE'
      std::is_trivially_copy_constructible<T>::value
      ~~~~~^
    ../libs/optional/tl/optional.hpp:388:71: error: 'T' does not refer to a value
    template <class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>
                                                                          ^
    ../libs/optional/tl/optional.hpp:60:40: note: expanded from macro 'TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE'
      std::is_trivially_copy_constructible<T>::value
                                           ^
    ../libs/optional/tl/optional.hpp:388:17: note: declared here
    template <class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>
                    ^
    ../libs/optional/tl/optional.hpp:388:27: error: no type named 'value' in the global namespace
    template <class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ../libs/optional/tl/optional.hpp:60:44: note: expanded from macro 'TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE'
      std::is_trivially_copy_constructible<T>::value
                                             ~~^
    ../libs/optional/tl/optional.hpp:388:73: error: expected unqualified-id
    template <class T, bool = TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>
                                                                            ^
    ../libs/optional/tl/optional.hpp:395:8: error: no template named 'optional_copy_base'; did you mean 'optional_storage_base'?
    struct optional_copy_base<T, false> : optional_operations_base<T> {
           ^~~~~~~~~~~~~~~~~~
           optional_storage_base
    ../libs/optional/tl/optional.hpp:302:8: note: 'optional_storage_base' declared here
    struct optional_storage_base {
           ^
    ../libs/optional/tl/optional.hpp:398:3: error: C++ requires a type specifier for all declarations
      optional_copy_base() = default;
      ^~~~~~~~~~~~~~~~~~
    ../libs/optional/tl/optional.hpp:399:28: error: unknown type name 'optional_copy_base'; did you mean 'optional_storage_base'?
      optional_copy_base(const optional_copy_base &rhs) {
                               ^~~~~~~~~~~~~~~~~~
                               optional_storage_base
    ../libs/optional/tl/optional.hpp:395:8: note: 'optional_storage_base' declared here
    struct optional_copy_base<T, false> : optional_operations_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:399:3: error: C++ requires a type specifier for all declarations
      optional_copy_base(const optional_copy_base &rhs) {
      ^~~~~~~~~~~~~~~~~~
    ../libs/optional/tl/optional.hpp:407:22: error: unknown type name 'optional_copy_base'; did you mean 'optional_storage_base'?
      optional_copy_base(optional_copy_base &&rhs) = default;
                         ^~~~~~~~~~~~~~~~~~
                         optional_storage_base
    ../libs/optional/tl/optional.hpp:395:8: note: 'optional_storage_base' declared here
    struct optional_copy_base<T, false> : optional_operations_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:407:3: error: C++ requires a type specifier for all declarations
      optional_copy_base(optional_copy_base &&rhs) = default;
      ^~~~~~~~~~~~~~~~~~
    ../libs/optional/tl/optional.hpp:408:3: error: unknown type name 'optional_copy_base'; did you mean 'optional_storage_base'?
      optional_copy_base &operator=(const optional_copy_base &rhs) = default;
      ^~~~~~~~~~~~~~~~~~
      optional_storage_base
    ../libs/optional/tl/optional.hpp:395:8: note: 'optional_storage_base' declared here
    struct optional_copy_base<T, false> : optional_operations_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:408:39: error: unknown type name 'optional_copy_base'; did you mean 'optional_storage_base'?
      optional_copy_base &operator=(const optional_copy_base &rhs) = default;
                                          ^~~~~~~~~~~~~~~~~~
                                          optional_storage_base
    ../libs/optional/tl/optional.hpp:395:8: note: 'optional_storage_base' declared here
    struct optional_copy_base<T, false> : optional_operations_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:409:3: error: unknown type name 'optional_copy_base'; did you mean 'optional_storage_base'?
      optional_copy_base &operator=(optional_copy_base &&rhs) = default;
      ^~~~~~~~~~~~~~~~~~
      optional_storage_base
    ../libs/optional/tl/optional.hpp:395:8: note: 'optional_storage_base' declared here
    struct optional_copy_base<T, false> : optional_operations_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:409:33: error: unknown type name 'optional_copy_base'; did you mean 'optional_storage_base'?
      optional_copy_base &operator=(optional_copy_base &&rhs) = default;
                                    ^~~~~~~~~~~~~~~~~~
                                    optional_storage_base
    ../libs/optional/tl/optional.hpp:395:8: note: 'optional_storage_base' declared here
    struct optional_copy_base<T, false> : optional_operations_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:418:32: error: no template named 'is_trivially_move_constructible' in namespace 'std'; did you mean 'is_trivially_destructible'?
    template <class T, bool = std::is_trivially_move_constructible<T>::value>
                              ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                   is_trivially_destructible
    /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:1204:12: note: 'is_trivially_destructible' declared here
        struct is_trivially_destructible
               ^
    ../libs/optional/tl/optional.hpp:419:29: error: no template named 'optional_copy_base'; did you mean 'optional_move_base'?
    struct optional_move_base : optional_copy_base<T> {
                                ^~~~~~~~~~~~~~~~~~
                                optional_move_base
    ../libs/optional/tl/optional.hpp:419:8: note: 'optional_move_base' declared here
    struct optional_move_base : optional_copy_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:420:9: error: no template named 'optional_copy_base'; did you mean 'optional_move_base'?
      using optional_copy_base<T>::optional_copy_base;
            ^~~~~~~~~~~~~~~~~~
            optional_move_base
    ../libs/optional/tl/optional.hpp:419:8: note: 'optional_move_base' declared here
    struct optional_move_base : optional_copy_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:425:58: error: no template named 'optional_copy_base'; did you mean 'optional_move_base'?
    template <class T> struct optional_move_base<T, false> : optional_copy_base<T> {
                                                             ^~~~~~~~~~~~~~~~~~
                                                             optional_move_base
    ../libs/optional/tl/optional.hpp:419:8: note: 'optional_move_base' declared here
    struct optional_move_base : optional_copy_base<T> {
           ^
    ../libs/optional/tl/optional.hpp:426:9: error: no template named 'optional_copy_base'; did you mean 'optional_move_base'?
      using optional_copy_base<T>::optional_copy_base;
            ^~~~~~~~~~~~~~~~~~
            optional_move_base
    ../libs/optional/tl/optional.hpp:419:8: note: 'optional_move_base' declared here
    struct optional_move_base : optional_copy_base<T> {
           ^
    fatal error: too many errors emitted, stopping now [-ferror-limit=]
    20 errors generated.
    
    
  • Play nice with CMake add_subdirectory

    Play nice with CMake add_subdirectory

    Enable use of tl::optional<T> purely as a library with CMake's add_subdirectory. The default configuration works are before.

    • OPTIONAL_ENABLE_TESTS make building tests optional, enabled by default
    • OPTIONAL_ENABLE_DOCS make building documentation optional, enabled by default
  • tl::optional cannot be used with exceptions disabled

    tl::optional cannot be used with exceptions disabled

    It's not possible to use tl::optional with exceptions disabled. It would be useful for code that is required to compile without exception support if this were possible. With libstdc++, abort is called instead for conditions that would raise an exception.

    It unfortunately varies across compilers how to detect if exception support has been disabled, but in a third party variant implementation this is done by https://github.com/mpark/variant/blob/d1cdfdd3f2ed80710ba4d671fe6bffaa3e28201a/v1.4.0/variant.hpp#L270 with __has_feature defined for non-clang compilers as https://github.com/mpark/variant/blob/d1cdfdd3f2ed80710ba4d671fe6bffaa3e28201a/v1.4.0/variant.hpp#L232.

  • memory leaks and 'use after move' bugs inside assignment operators implementation

    memory leaks and 'use after move' bugs inside assignment operators implementation

    Hi,

    The bugs could be triggered with the following code:

    #include <tl/optional.hpp>
    #include <vector>
    #include <iostream>
    
    struct VectorOfIntWrapper
    {                              
        VectorOfIntWrapper(std::vector<int>&& other) : data(std::move(other)) {}
        void operator=(std::vector<int>&& other){ data = std::move(other); }
        std::vector<int> data;
    };
    
    int main()
    {
        tl::optional<VectorOfIntWrapper> fst = VectorOfIntWrapper{{1, 2, 3, 4}};
        tl::optional<std::vector<int>> sec = std::vector<int>{5, 6, 7, 8};      
        fst = std::move(sec);  // memory leak and invalid result
        std::cout << fst->data.size(); // prints 0
    }
    

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

    Issues could be fixed by not calling this->construct(...) in case the value is already present(by adding 'else' in lines 1186 and 1208):

      optional &operator=(optional<U> &&rhs) {
        if (has_value()) {
          if (rhs.has_value()) {
            this->m_value = std::move(*rhs);
          } else {
            this->hard_reset();
          }
        }
        else if (rhs.has_value()) {
          this->construct(std::move(*rhs));
        }
    
        return *this;
      }
  • add a value_or_eval similar to boost::optional

    add a value_or_eval similar to boost::optional

    Hi TL Thanks for your great library.

    Was wondering if you had considered a value_or_eval, similar to the existing value_or, which returns the current value if it exists, or returns value from a lambda etc, but only executes if the optional is empty.

    The point is to enable lazy evaluation, especially for expensive calculations.

    (This exists in boost::optional, but not sure if there was a reason not to include it in the std.)

    Thanks.

    Here is a implementation from boost 1.61 for example

        template <typename F>
        value_type value_or_eval ( F f ) const&
          {
            if (this->is_initialized())
              return get();
            else
              return f();
          }
          
        template <typename F>
        value_type value_or_eval ( F f ) &&
          {
            if (this->is_initialized())
              return boost::move(get());
            else
              return f();
          }
    
  • Make constexpr swap

    Make constexpr swap

    Hello, please make tl::optional constexpr swappable. In std::optional this implemented (since C++20).

    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2231r1.html

  • add value_or_cast<U>

    add value_or_cast

    add support for value_or_cast

    this is useful when using unsigned and signed types

    tl::optional<size_t> x = get_PossibleVal();
    

    example 1

    // equivalent to:    float a = x.hasValue() ? *x : static_cast<size_t>(NAN);
    // ERROR: size_t is unsigned type and will convert to size_t 0
    // ERROR: resulting float is [value or 0] instead of [value or NAN]
    float a = x.value_or<float>(NAN);
    
    // equivalent to:    float b = x.hasValue() ? static_cast<float>(*x) : NAN;
    // resulting float is value or NAN
    float b = x.value_or_cast<float>(NAN);
    

    example 2

    // equivalent to:    float a = x.hasValue() ? *x : static_cast<size_t>(-1);
    // ERROR: size_t is unsigned type and will convert to size_t 18446744073709551615
    // ERROR: resulting float is [value or 1.8446744073709551615] instead of [value or -1]
    float a = x.value_or<float>(-1);
    
    // equivalent to:    float b = x.hasValue() ? static_cast<float>(*x) : -1;
    // resulting float is value or -1
    float b = x.value_or_cast<float>(-1);
    

    new code

            /// Returns the stored value if there is one, otherwise returns `u`
            template <class U> constexpr U value_or_cast(U &&u) const & {
                static_assert(std::is_copy_constructible<U>::value &&
                              std::is_convertible<T, U>::value,
                              "U must be copy constructible and convertible from T");
                return has_value() ? static_cast<U>(**this) : std::forward<U>(u);
            }
    
            /// Returns the stored value if there is one, otherwise returns `u`
            template <class U> TL_OPTIONAL_11_CONSTEXPR U value_or_cast(U &&u) && {
                static_assert(std::is_move_constructible<U>::value &&
                              std::is_convertible<T, U>::value,
                              "U must be move constructible and convertible from T");
                return has_value() ? static_cast<U>(**this) : std::forward<U>(u);
            }
    
            /// Returns the stored value if there is one, otherwise returns `u`
            template <class U> constexpr U value_or_cast(U &&u) const & noexcept {
                static_assert(std::is_copy_constructible<U>::value &&
                              std::is_convertible<T, U>::value,
                              "U must be copy constructible and convertible from T");
                return has_value() ? static_cast<U>(**this) : std::forward<U>(u);
            }
    
            /// \group value_or_cast
            template <class U> TL_OPTIONAL_11_CONSTEXPR U value_or_cast(U &&u) && noexcept {
                static_assert(std::is_move_constructible<U>::value &&
                              std::is_convertible<T, U>::value,
                              "U must be move constructible and convertible from T");
                return has_value() ? static_cast<U>(**this) : std::forward<U>(u);
            }
    
optional lite - A C++17-like optional, a nullable object for C++98, C++11 and later in a single-file header-only library

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

Jun 7, 2022
A standard conforming C++20 implementation of std::optional.

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

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

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.

Dec 2, 2019
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

Jun 11, 2022
C++ library for Unicode Strings, with value semantics on reference-counted shared slices

strpp - StringPlusPlus - pronounced "strip" A value-oriented character string library with reference-counting to manage shared slices Features By-valu

Apr 27, 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

Jun 20, 2022
Range library for C++14/17/20, basis for C++20's std::ranges

range-v3 Range library for C++14/17/20. This code was the basis of a formal proposal to add range support to the C++ standard library. That proposal e

Jun 14, 2022
Allows a programmer to print table-like outputs over std::ostream.

tableprinter Allows a programmer to print table-like outputs over std::ostream. It is a header only library. No other dependency than STL. Provides re

Apr 15, 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

Jun 16, 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

Jun 16, 2022
Bsl - Rust 2018 and C++20, "constexpr everything", AUTOSAR compliant header-only library intended to support the development of critical systems applications
Bsl - Rust 2018 and C++20,

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

Jun 18, 2022
GNU Scientific Library with CMake build support and AMPL bindings

GSL - GNU Scientific Library This is GSL, the GNU Scientific Library, a collection of numerical routines for scientific computing. GSL is free softwar

Jun 16, 2022
C++ STL in the Windows Kernel with C++ Exception Support

C++ STL in Windows Drivers This project uses MSVC C++ STL in a Windows Kernel Driver. In this solution jxystl.lib is implemented as a kernel-tuned, po

Jun 10, 2022
Guidelines Support Library

GSL: Guidelines Support Library The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the C++ Core Guideline

Jun 20, 2022
Guidelines Support Library

GSL: Guidelines Support Library The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the C++ Core Guideline

Jun 14, 2022
this lib with 26 template container and 10 kinds of algorithm, it is a good lib for study and usage

simple stl this lib simplify the achievement detail of common container, but add the container variety, the whole code partily follow Google Style. Em

Mar 10, 2022
Quick and dirty templating and docs generation.

Rader Quick and dirty templating and docs generation. Rader is a pre-processing (or post-processing) utility written in portable C++ 20 (only using st

Dec 19, 2021
LLVM libc++ without exception and RTTI, specifically for Android.

libc++ LLVM libc++, specifically for Android, removing exception and RTTI support. Source code is extracted from AOSP's llvm-project repository: git c

Jun 18, 2022