Compare commits

..

23 Commits

Author SHA1 Message Date
Andrzej Krzemienski 1fb60cb53b fix bug in copy construction of optional<bool> 2026-05-11 13:58:35 +02:00
Andrzej Krzemienski ecb241a919 tests: remove all -Wall warnings 2026-02-25 22:49:18 +01:00
Andrzej Krzemieński ff710d113c Merge pull request #145 from alandefreitas/fix/maybe-uninitialized-pragma
fix: add -Wmaybe-uninitialized pragma to union storage constructors
2026-02-25 17:42:43 +01:00
Alan de Freitas 88e2378c8a Add -Wmaybe-uninitialized pragma to union storage constructors
GCC 7+ produces false-positive -Wmaybe-uninitialized warnings at -O3
when deeply inlining through union constructors that initialize one
member while another (dummy_) exists. This is the same class of false
positive addressed in boostorg/variant2#55.

The pragmas are placed around the forwarding constructors in both
constexpr_union_storage_t and fallback_union_storage_t.
2026-02-24 12:11:51 -05:00
Andrzej Krzemienski fa52755c88 docs update 2026-02-20 16:14:53 +01:00
Andrzej Krzemienski 76be15bfeb update release notes 2026-02-18 21:10:45 +01:00
Andrzej Krzemienski 5d8e50a9aa add conversion from optional T to optional ref T 2026-02-18 16:52:52 +01:00
Andrzej Krzemienski 37513ddbbf remove traces of Boost.Assert 2026-02-18 13:23:48 +01:00
Andrzej Krzemienski 953b678b39 docs: minor fixes 2026-02-17 16:24:55 +01:00
Andrzej Krzemienski b2057c8dfe MSVC 14.1 fix -- 3rd attempt 2026-02-16 15:40:05 +01:00
Andrzej Krzemienski 1c13f5f724 MSVC 14.1 fix -- 2nd attempt 2026-02-16 13:20:03 +01:00
Andrzej Krzemienski aa1cf1e76c Work around the MSVC 14.1 bug 2026-02-16 01:13:53 +01:00
Andrzej Krzemienski 938502da88 fix bug with factories + conversions 2026-02-10 22:02:50 +01:00
Andrzej Krzemienski 046357ce54 Add more robust constexpr support 2026-02-10 19:30:11 +01:00
Andrzej Krzemienski b6a57cdb46 docs: fixed release notes 2026-02-07 23:05:25 +01:00
Andrzej Krzemienski dd0e9d8a72 temporarily disable the constexpr implementation 2026-02-07 13:56:40 +01:00
Andrzej Krzemienski c81b9b098b fix constexpr reset 2026-02-07 13:36:08 +01:00
Andrzej Krzemienski 7b078be18d demove deprecation warnings 2026-02-07 13:23:04 +01:00
Andrzej Krzemienski 3df23370e6 make optional constexpr in C++14 2026-02-07 02:12:24 +01:00
Andrzej Krzemieński bfdf0c73f9 Merge pull request #139 from Flamefire/patch-1
Fix node 20 issue on GHA CI
2024-12-08 17:21:21 +01:00
Alexander Grund e1c6b5b737 Update containers 2024-12-08 14:43:18 +01:00
Alexander Grund 1a8c2dcafd Use hosted node 2024-12-08 13:11:03 +01:00
Alexander Grund 6134d0c274 Fix node 20 issue on GHA CI 2024-12-07 19:43:22 +01:00
48 changed files with 2441 additions and 617 deletions
+15 -14
View File
@@ -10,7 +10,6 @@ on:
env: env:
UBSAN_OPTIONS: print_stacktrace=1 UBSAN_OPTIONS: print_stacktrace=1
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs: jobs:
posix: posix:
@@ -69,8 +68,7 @@ jobs:
address-model: 32,64 address-model: 32,64
- toolset: gcc-13 - toolset: gcc-13
cxxstd: "03,11,14,17,20,2b" cxxstd: "03,11,14,17,20,2b"
os: ubuntu-latest os: ubuntu-24.04
container: ubuntu:23.04
install: g++-13-multilib install: g++-13-multilib
address-model: 32,64 address-model: 32,64
- toolset: clang - toolset: clang
@@ -144,37 +142,40 @@ jobs:
- toolset: clang - toolset: clang
compiler: clang++-16 compiler: clang++-16
cxxstd: "03,11,14,17,20,2b" cxxstd: "03,11,14,17,20,2b"
container: ubuntu:23.04 os: ubuntu-24.04
os: ubuntu-latest
install: clang-16 install: clang-16
- toolset: clang - toolset: clang
compiler: clang++-17 compiler: clang++-17
cxxstd: "03,11,14,17,20,2b" cxxstd: "03,11,14,17,20,2b"
container: ubuntu:23.10 os: ubuntu-24.04
os: ubuntu-latest
install: clang-17 install: clang-17
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-12
- toolset: clang - toolset: clang
cxxstd: "03,11,14,17,20,2b" cxxstd: "03,11,14,17,20,2b"
os: macos-13 os: macos-13
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
container: ${{matrix.container}} container:
image: ${{matrix.container}}
volumes:
- /node20217:/node20217:rw,rshared
- ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
defaults: defaults:
run: run:
shell: bash shell: bash
steps: steps:
- uses: actions/checkout@v3
- name: Setup container environment - name: Setup container environment
if: matrix.container if: matrix.container
run: | run: |
apt-get update apt-get update
apt-get -y install sudo python3 git g++ apt-get -y install sudo python3 git g++ curl
if [[ "${{matrix.container}}" == "ubuntu:1"* ]]; then
# Node 20 doesn't work with Ubuntu 16/18 glibc: https://github.com/actions/checkout/issues/1590
curl -sL https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz | tar -xJ --strip-components 1 -C /node20217
fi
- uses: actions/checkout@v4
- name: Install packages - name: Install packages
if: matrix.install if: matrix.install
+2 -2
View File
@@ -1,8 +1,8 @@
[library Boost.Optional [library Boost.Optional
[quickbook 1.4] [quickbook 1.7]
[authors [Cacciola Carballal, Fernando Luis]] [authors [Cacciola Carballal, Fernando Luis]]
[copyright 2003-2007 Fernando Luis Cacciola Carballal] [copyright 2003-2007 Fernando Luis Cacciola Carballal]
[copyright 2014-2024 Andrzej Krzemie&#324;ski] [copyright 2014-2026 Andrzej Krzemieński]
[category miscellaneous] [category miscellaneous]
[id optional] [id optional]
[dirname optional] [dirname optional]
-1
View File
@@ -124,7 +124,6 @@ Suppose we want to implement a ['lazy load] optimization. This is because we do
`optional`'s default constructor creates an uninitialized optional. No call to `Resource`'s default constructor is attempted. `Resource` doesn't have to be __STD_DEFAULT_CONSTRUCTIBLE__. In function `getResource` we first check if `resource_` is initialized. This time we do not use the contextual conversion to `bool`, but a comparison with `boost::none`. These two ways are equivalent. Function `emplace` initializes the optional in-place by perfect-forwarding the arguments to the constructor of `Resource`. No copy- or move-construction is involved here. `Resource` doesn't even have to be `MoveConstructible`. `optional`'s default constructor creates an uninitialized optional. No call to `Resource`'s default constructor is attempted. `Resource` doesn't have to be __STD_DEFAULT_CONSTRUCTIBLE__. In function `getResource` we first check if `resource_` is initialized. This time we do not use the contextual conversion to `bool`, but a comparison with `boost::none`. These two ways are equivalent. Function `emplace` initializes the optional in-place by perfect-forwarding the arguments to the constructor of `Resource`. No copy- or move-construction is involved here. `Resource` doesn't even have to be `MoveConstructible`.
[note Function `emplace` is only available on compilers that support rvalue references and variadic templates. If your compiler does not support these features and you still need to avoid any move-constructions, use [link boost_optional.design.in_place_factories In-Place Factories].]
[endsect] [endsect]
+12
View File
@@ -50,6 +50,18 @@ In the general case, the internal representation is something equivalent to:
alignas(T) char _value [sizeof(T)]; alignas(T) char _value [sizeof(T)];
}; };
or:
template <typename T>
class Optional
{
bool _has_value = false;
union {
T _value;
DummyType _non_value;
};
};
Next, because we need to pass around these "optional" `int`s as normal `int`s, Next, because we need to pass around these "optional" `int`s as normal `int`s,
like returning them from functions, when copying, we need to copy `_has_value`, like returning them from functions, when copying, we need to copy `_has_value`,
which indicates whether we have the value or not, and, if we do have value, and which indicates whether we have the value or not, and, if we do have value, and
+3 -1
View File
@@ -27,7 +27,7 @@ rather than the reference itself.
On compilers that do not conform to Standard C++ rules of reference binding, On compilers that do not conform to Standard C++ rules of reference binding,
some operations on optional references are disabled in order to prevent subtle some operations on optional references are disabled in order to prevent subtle
bugs. For more details see bugs. For more details see
[link boost_optional.dependencies_and_portability.optional_reference_binding Dependencies and Portability section]. [link optional_reference_binding Dependencies and Portability section].
] ]
[heading Rvalue references] [heading Rvalue references]
@@ -39,6 +39,8 @@ Rvalue references and lvalue references to const have the ability in C++ to exte
[endsect] [endsect]
[#optional_ref_rebinding_semantics]
[section Rebinding semantics for assignment of optional references] [section Rebinding semantics for assignment of optional references]
If you assign to an ['uninitialized ] `optional<T&>` the effect is to bind (for If you assign to an ['uninitialized ] `optional<T&>` the effect is to bind (for
+4 -2
View File
@@ -1,5 +1,5 @@
[section In-Place Factories] [section:in_place_factories In-Place Factories][#boost_optional_factories]
One of the typical problems with wrappers and containers is that their One of the typical problems with wrappers and containers is that their
interfaces usually provide an operation to initialize or assign the interfaces usually provide an operation to initialize or assign the
@@ -136,4 +136,6 @@ In-place factories can be used generically by the wrapper and user as follows:
The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYPED_IN_PLACE_FACTORY_HPP__ The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYPED_IN_PLACE_FACTORY_HPP__
[endsect] [caution The support for in-place factories is deprecated. Use constructor taking `in_place_init` tag and function `.emplace()` instead.]
[endsect:in_place_factories]
+1 -1
View File
@@ -8,7 +8,7 @@ The very minimum requirement of `optional<T>` is that `T` is a complete type and
assert(!o); // assert(!o); //
o.value(); // always throws o.value(); // always throws
But this is practically useless. In order for `optional<T>` to be able to do anything useful and offer all the spectrum of ways of accessing the contained value, `T` needs to have at least one accessible constructor. In that case you need to initialize the optional object with function `emplace()`, or if your compiler does not support it, resort to [link boost_optional.design.in_place_factories In-Place Factories]: But this is practically useless. In order for `optional<T>` to be able to do anything useful and offer all the spectrum of ways of accessing the contained value, `T` needs to have at least one accessible constructor. In that case you need to initialize the optional object with function `emplace()`, or if your compiler does not support it, resort to [link boost_optional_factories In-Place Factories]:
optional<T> o; optional<T> o;
o.emplace("T", "ctor", "params"); o.emplace("T", "ctor", "params");
+14 -3
View File
@@ -2,7 +2,7 @@
Boost.Optional Boost.Optional
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
Copyright (c) 2015 Andrzej Krzemienski Copyright (c) 2015 Andrzej Krzemieński
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
@@ -15,14 +15,25 @@
``` ```
namespace boost { namespace boost {
class none_t {/* see below */}; class none_t
{
friend constexpr bool operator==(none_t, none_t) = default;
/* see below */
};
inline constexpr none_t none (/* see below */); inline constexpr none_t none (/* see below */);
} // namespace boost } // namespace boost
``` ```
Class `none_t` is meant to serve as a tag for selecting appropriate overloads of from `optional`'s interface. It is an empty, trivially copyable class with disabled default constructor. Class `none_t` is meant to serve as a tag for selecting appropriate overloads of from `optional`'s interface.
It is an empty class.
It is [@https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable.html trivially copyable].
It is ['not] [@https://en.cppreference.com/w/cpp/named_req/DefaultConstructible default-constructible].
It models concept [@https://en.cppreference.com/w/cpp/concepts/equality_comparable `std::equality_comparable`].
Constant `none` is used to indicate an optional object that does not contain a value in initialization, assignment and relational operations of `optional`. Constant `none` is used to indicate an optional object that does not contain a value in initialization, assignment and relational operations of `optional`.
+43 -42
View File
@@ -95,10 +95,10 @@
namespace boost { namespace boost {
class in_place_init_t { /* see below */ } ; class in_place_init_t { /* see below */ } ;
const in_place_init_t in_place_init ( /* see below */ ) ; inline constexpr in_place_init_t in_place_init ( /* see below */ ) ;
class in_place_init_if_t { /*see below*/ } ; class in_place_init_if_t { /*see below*/ } ;
const in_place_init_if_t in_place_init_if ( /*see below*/ ) ; inline constexpr in_place_init_if_t in_place_init_if ( /*see below*/ ) ;
} }
@@ -123,33 +123,33 @@ They are empty, trivially copyable classes with disabled default constructor.
typedef T * pointer_type ; typedef T * pointer_type ;
typedef T const* pointer_const_type ; typedef T const* pointer_const_type ;
optional () noexcept ; ``[link reference_optional_constructor __GO_TO__]`` constexpr optional () noexcept ; ``[link reference_optional_constructor __GO_TO__]``
optional ( none_t ) noexcept ; ``[link reference_optional_constructor_none_t __GO_TO__]`` constexpr optional ( none_t ) noexcept ; ``[link reference_optional_constructor_none_t __GO_TO__]``
optional ( T const& v ) ; ``[link reference_optional_constructor_value __GO_TO__]`` constexpr optional ( T const& v ) ; ``[link reference_optional_constructor_value __GO_TO__]``
optional ( T&& v ) ; ``[link reference_optional_constructor_move_value __GO_TO__]`` constexpr optional ( T&& v ) ; ``[link reference_optional_constructor_move_value __GO_TO__]``
optional ( bool condition, T const& v ) ; ``[link reference_optional_constructor_bool_value __GO_TO__]`` constexpr optional ( bool condition, T const& v ) ; ``[link reference_optional_constructor_bool_value __GO_TO__]``
optional ( optional const& rhs ) ; ``[link reference_optional_constructor_optional __GO_TO__]`` constexpr optional ( optional const& rhs ) ; ``[link reference_optional_constructor_optional __GO_TO__]``
optional ( optional&& rhs ) noexcept(``['see below]``) ; ``[link reference_optional_move_constructor_optional __GO_TO__]`` constexpr optional ( optional&& rhs ) noexcept(``['see below]``) ; ``[link reference_optional_move_constructor_optional __GO_TO__]``
template<class U> explicit optional ( optional<U> const& rhs ) ; ``[link reference_optional_constructor_other_optional __GO_TO__]`` template<class U> constexpr explicit optional ( optional<U> const& rhs ) ; ``[link reference_optional_constructor_other_optional __GO_TO__]``
template<class U> explicit optional ( optional<U>&& rhs ) ; ``[link reference_optional_move_constructor_other_optional __GO_TO__]`` template<class U> constexpr explicit optional ( optional<U>&& rhs ) ; ``[link reference_optional_move_constructor_other_optional __GO_TO__]``
template<class... Args> explicit optional ( in_place_init_t, Args&&... args ) ; ``[link reference_optional_in_place_init __GO_TO__]`` template<class... Args> constexpr explicit optional ( in_place_init_t, Args&&... args ) ; ``[link reference_optional_in_place_init __GO_TO__]``
template<class... Args> explicit optional ( in_place_init_if_t, bool condition, Args&&... args ) ; ``[link reference_optional_in_place_init_if __GO_TO__]`` template<class... Args> constexpr explicit optional ( in_place_init_if_t, bool condition, Args&&... args ) ; ``[link reference_optional_in_place_init_if __GO_TO__]``
template<class InPlaceFactory> explicit optional ( InPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]`` template<class InPlaceFactory> explicit optional ( InPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]``
template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]`` template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]``
optional& operator = ( none_t ) noexcept ; ``[link reference_optional_operator_equal_none_t __GO_TO__]`` constexpr optional& operator = ( none_t ) noexcept ; ``[link reference_optional_operator_equal_none_t __GO_TO__]``
optional& operator = ( T const& v ) ; ``[link reference_optional_operator_equal_value __GO_TO__]`` optional& operator = ( T const& v ) ; ``[link reference_optional_operator_equal_value __GO_TO__]``
@@ -169,44 +169,45 @@ They are empty, trivially copyable classes with disabled default constructor.
template<class TypedInPlaceFactory> optional& operator = ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_operator_equal_factory __GO_TO__]`` template<class TypedInPlaceFactory> optional& operator = ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_operator_equal_factory __GO_TO__]``
T const& get() const ; ``[link reference_optional_get __GO_TO__]`` constexpr T const& get() const ; ``[link reference_optional_get __GO_TO__]``
T& get() ; ``[link reference_optional_get __GO_TO__]`` constexpr T& get() ; ``[link reference_optional_get __GO_TO__]``
T const* operator ->() const ; ``[link reference_optional_operator_arrow __GO_TO__]`` constexpr T const* operator ->() const ; ``[link reference_optional_operator_arrow __GO_TO__]``
T* operator ->() ; ``[link reference_optional_operator_arrow __GO_TO__]`` constexpr T* operator ->() ; ``[link reference_optional_operator_arrow __GO_TO__]``
T const& operator *() const& ; ``[link reference_optional_operator_asterisk __GO_TO__]`` constexpr T const& operator *() const& ; ``[link reference_optional_operator_asterisk __GO_TO__]``
T& operator *() & ; ``[link reference_optional_operator_asterisk __GO_TO__]`` constexpr T& operator *() & ; ``[link reference_optional_operator_asterisk __GO_TO__]``
T&& operator *() && ; ``[link reference_optional_operator_asterisk_move __GO_TO__]`` constexpr T&& operator *() && ; ``[link reference_optional_operator_asterisk_move __GO_TO__]``
T const& value() const& ; ``[link reference_optional_value __GO_TO__]`` constexpr T const& value() const& ; ``[link reference_optional_value __GO_TO__]``
T& value() & ; ``[link reference_optional_value __GO_TO__]`` constexpr T& value() & ; ``[link reference_optional_value __GO_TO__]``
T&& value() && ; ``[link reference_optional_value_move __GO_TO__]`` constexpr T&& value() && ; ``[link reference_optional_value_move __GO_TO__]``
template<class U> T value_or( U && v ) const& ; ``[link reference_optional_value_or __GO_TO__]`` template<class U> constexpr T value_or( U && v ) const& ; ``[link reference_optional_value_or __GO_TO__]``
template<class U> T value_or( U && v ) && ; ``[link reference_optional_value_or_move __GO_TO__]`` template<class U> constexpr T value_or( U && v ) && ; ``[link reference_optional_value_or_move __GO_TO__]``
template<class F> T value_or_eval( F f ) const& ; ``[link reference_optional_value_or_call __GO_TO__]`` template<class F> constexpr T value_or_eval( F f ) const& ; ``[link reference_optional_value_or_call __GO_TO__]``
template<class F> T value_or_eval( F f ) && ; ``[link reference_optional_value_or_call_move __GO_TO__]`` template<class F> constexpr T value_or_eval( F f ) && ; ``[link reference_optional_value_or_call_move __GO_TO__]``
template<class F> auto map( F f ) const& -> ``['see below]``; ``[link reference_optional_map __GO_TO__]`` template<class F> constexpr auto map( F f ) const& -> ``['see below]``; ``[link reference_optional_map __GO_TO__]``
template<class F> auto map( F f ) & -> ``['see below]``; ``[link reference_optional_map __GO_TO__]`` template<class F> constexpr auto map( F f ) & -> ``['see below]``; ``[link reference_optional_map __GO_TO__]``
template<class F> auto map( F f ) && -> ``['see below]``; ``[link reference_optional_map_move __GO_TO__]`` template<class F> constexpr auto map( F f ) && -> ``['see below]``; ``[link reference_optional_map_move __GO_TO__]``
template<class F> auto flat_map( F f ) const& -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]`` template<class F> constexpr auto flat_map( F f ) const& -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]``
template<class F> auto flat_map( F f ) & -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]`` template<class F> constexpr auto flat_map( F f ) & -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]``
template<class F> auto flat_map( F f ) && -> ``['see below]``; ``[link reference_optional_flat_map_move __GO_TO__]`` template<class F> constexpr auto flat_map( F f ) && -> ``['see below]``; ``[link reference_optional_flat_map_move __GO_TO__]``
constexpr operator optional<T&>() & noexcept; ``[link reference_optional_conversion_to_ref __GO_TO__]``
constexpr operator optional<T const&>() const& noexcept; ``[link reference_optional_conversion_to_ref __GO_TO__]``
T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]`` T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]``
T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]`` T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]``
bool has_value() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]`` constexpr bool has_value() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]``
explicit operator bool() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]`` constexpr explicit operator bool() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]``
bool operator!() const noexcept ; ``[link reference_optional_operator_not __GO_TO__]`` constexpr void reset() noexcept ; ``[link reference_optional_reset __GO_TO__]``
void reset() noexcept ; ``[link reference_optional_reset __GO_TO__]``
// deprecated methods // deprecated methods
@@ -214,7 +215,7 @@ They are empty, trivially copyable classes with disabled default constructor.
void reset ( T const& ) ; ``[link reference_optional_reset_value __GO_TO__]`` void reset ( T const& ) ; ``[link reference_optional_reset_value __GO_TO__]``
// (deprecated) // (deprecated)
bool is_initialized() const ; ``[link reference_optional_is_initialized __GO_TO__]`` constexpr bool is_initialized() const ; ``[link reference_optional_is_initialized __GO_TO__]``
// (deprecated) // (deprecated)
T const& get_value_or( T const& default ) const ; ``[link reference_optional_get_value_or_value __GO_TO__]`` T const& get_value_or( T const& default ) const ; ``[link reference_optional_get_value_or_value __GO_TO__]``
@@ -239,9 +240,9 @@ They are empty, trivially copyable classes with disabled default constructor.
typedef T* pointer_type; typedef T* pointer_type;
typedef T* pointer_const_type; // no const propagation typedef T* pointer_const_type; // no const propagation
optional () noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]`` constexpr optional () noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]``
optional ( none_t ) noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]`` constexpr optional ( none_t ) noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]``
template<class R> optional(R&& r) noexcept ; ``[link reference_optional_ref_value_ctor __GO_TO__]`` template<class R> optional(R&& r) noexcept ; ``[link reference_optional_ref_value_ctor __GO_TO__]``
+88 -74
View File
@@ -2,6 +2,7 @@
Boost.Optional Boost.Optional
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
Copyright (C) 2014 - 2026 Andrzej Krzemieński.
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
@@ -23,40 +24,40 @@ __SPACE__
[#reference_optional_constructor] [#reference_optional_constructor]
[: `optional<T>::optional() noexcept;`] [: `constexpr optional<T>::optional() noexcept;`]
* [*Effect:] Default-Constructs an `optional`. * [*Postconditions:] `*this` does ['not] contain a value (is "uninitialized").
* [*Postconditions:] `*this` is [_uninitialized]. * [*Remarks:] No contained value is initialized. For every object type `T` these constructors are core constant expressions.
* [*Notes:] T's default constructor [_is not] called.
* [*Example:] * [*Example:]
`` ``
optional<T> def ; optional<T> oN ;
assert ( !def ) ; assert ( !oN ) ;
`` ``
__SPACE__ __SPACE__
[#reference_optional_constructor_none_t] [#reference_optional_constructor_none_t]
[: `constexpr optional<T>::optional( none_t ) noexcept;`]
[: `optional<T>::optional( none_t ) noexcept;`] * [*Postconditions:] `*this` does ['not] contain a value (is "uninitialized").
* [*Remarks:] No contained value is initialized. For every object type `T` these constructors are core constant expressions. The expression
* [*Effect:] Constructs an `optional` uninitialized.
* [*Postconditions:] `*this` is [_uninitialized].
* [*Notes:] `T`'s default constructor [_is not] called. The expression
`boost::none` denotes an instance of `boost::none_t` that can be used as `boost::none` denotes an instance of `boost::none_t` that can be used as
the parameter. the parameter.
* [*Example:] * [*Example:]
`` ``
#include <boost/none.hpp> #include <boost/none.hpp>
optional<T> n(none) ; optional<T> n(none) ;
assert ( !n ) ; assert ( !n ) ;
assert ( n == none ) ;
`` ``
__SPACE__ __SPACE__
[#reference_optional_constructor_value] [#reference_optional_constructor_value]
[: `optional<T>::optional( T const& v )`] [: `constexpr optional<T>::optional( T const& v )`]
* [*Requires:] `is_copy_constructible<T>::value` is `true`. * [*Requires:] `is_copy_constructible<T>::value` is `true`.
* [*Effect:] Directly-Constructs an `optional`. * [*Effect:] Directly-Constructs an `optional`.
@@ -78,7 +79,7 @@ __SPACE__
[#reference_optional_constructor_move_value] [#reference_optional_constructor_move_value]
[: `optional<T>::optional( T&& v )`] [: `constexpr optional<T>::optional( T&& v )`]
* [*Requires:] `is_move_constructible<T>::value` is `true`. * [*Requires:] `is_move_constructible<T>::value` is `true`.
* [*Effect:] Directly-Move-Constructs an `optional`. * [*Effect:] Directly-Move-Constructs an `optional`.
@@ -99,7 +100,7 @@ __SPACE__
[#reference_optional_constructor_bool_value] [#reference_optional_constructor_bool_value]
[: `optional<T>::optional( bool condition, T const& v ) ;` ] [: `constexpr optional<T>::optional( bool condition, T const& v ) ;` ]
* If condition is true, same as: * If condition is true, same as:
@@ -114,7 +115,7 @@ __SPACE__
[#reference_optional_constructor_optional] [#reference_optional_constructor_optional]
[: `optional<T>::optional( optional const& rhs );`] [: `constexpr optional<T>::optional( optional const& rhs );`]
* [*Requires:] `is_copy_constructible<T>::value` is `true`. * [*Requires:] `is_copy_constructible<T>::value` is `true`.
* [*Effect:] Copy-Constructs an `optional`. * [*Effect:] Copy-Constructs an `optional`.
@@ -144,7 +145,7 @@ __SPACE__
[#reference_optional_move_constructor_optional] [#reference_optional_move_constructor_optional]
[: `optional<T>::optional( optional&& rhs ) noexcept(`['see below]`);`] [: `constexpr optional<T>::optional( optional&& rhs ) noexcept(`['see below]`);`]
* [*Requires:] `is_move_constructible<T>::value` is `true`. * [*Requires:] `is_move_constructible<T>::value` is `true`.
* [*Effect:] Move-constructs an `optional`. * [*Effect:] Move-constructs an `optional`.
@@ -178,7 +179,7 @@ __SPACE__
[#reference_optional_constructor_other_optional] [#reference_optional_constructor_other_optional]
[: `template<U> explicit optional<T>::optional( optional<U> const& rhs );`] [: `template<U> constexpr explicit optional<T>::optional( optional<U> const& rhs );`]
* [*Effect:] Copy-Constructs an `optional`. * [*Effect:] Copy-Constructs an `optional`.
* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its * [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its
@@ -202,7 +203,7 @@ __SPACE__
[#reference_optional_move_constructor_other_optional] [#reference_optional_move_constructor_other_optional]
[: `template<U> explicit optional<T>::optional( optional<U>&& rhs );`] [: `template<U> constexpr explicit optional<T>::optional( optional<U>&& rhs );`]
* [*Effect:] Move-constructs an `optional`. * [*Effect:] Move-constructs an `optional`.
* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its * [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its
@@ -226,7 +227,7 @@ __SPACE__
[#reference_optional_in_place_init] [#reference_optional_in_place_init]
[: `template<class... Args> explicit optional<T>::optional( in_place_init_t, Args&&... ars );`] [: `template<class... Args> constexpr explicit optional<T>::optional( in_place_init_t, Args&&... ars );`]
* [*Requires:] `is_constructible_v<T, Args&&...>` is `true`. * [*Requires:] `is_constructible_v<T, Args&&...>` is `true`.
* [*Effect:] Initializes the contained value as if direct-non-list-initializing an object of type `T` with the * [*Effect:] Initializes the contained value as if direct-non-list-initializing an object of type `T` with the
@@ -251,7 +252,7 @@ __SPACE__
[#reference_optional_in_place_init_if] [#reference_optional_in_place_init_if]
[: `template<class... Args> explicit optional<T>::optional( in_place_init_if_t, bool condition, Args&&... ars );`] [: `template<class... Args> constexpr explicit optional<T>::optional( in_place_init_if_t, bool condition, Args&&... ars );`]
* [*Requires:] `is_constructible_v<T, Args&&...>` is `true`. * [*Requires:] `is_constructible_v<T, Args&&...>` is `true`.
* [*Effect:] If `condition` is `true`, initializes the contained value as if direct-non-list-initializing an object of type `T` with the arguments `std::forward<Args>(args)...`. * [*Effect:] If `condition` is `true`, initializes the contained value as if direct-non-list-initializing an object of type `T` with the arguments `std::forward<Args>(args)...`.
@@ -281,7 +282,7 @@ factory.
* [*Postconditions: ] `*this` is [_initialized] and its value is ['directly given] * [*Postconditions: ] `*this` is [_initialized] and its value is ['directly given]
from the factory `f` (i.e., the value [_is not copied]). from the factory `f` (i.e., the value [_is not copied]).
* [*Throws:] Whatever the `T` constructor called by the factory throws. * [*Throws:] Whatever the `T` constructor called by the factory throws.
* [*Notes:] See [link boost_optional.design.in_place_factories In-Place Factories] * [*Notes:] See [link boost_optional_factories In-Place Factories]
* [*Exception Safety:] Exceptions can only be thrown during the call to * [*Exception Safety:] Exceptions can only be thrown during the call to
the `T` constructor used by the factory; in that case, this constructor has the `T` constructor used by the factory; in that case, this constructor has
no effect. no effect.
@@ -302,7 +303,7 @@ __SPACE__
[#reference_optional_operator_equal_none_t] [#reference_optional_operator_equal_none_t]
[: `optional& optional<T>::operator= ( none_t ) noexcept;`] [: `constexpr optional& optional<T>::operator= ( none_t ) noexcept;`]
* [*Effect:] If `*this` is initialized destroys its contained value. * [*Effect:] If `*this` is initialized destroys its contained value.
* [*Postconditions: ] `*this` is uninitialized. * [*Postconditions: ] `*this` is uninitialized.
@@ -502,7 +503,7 @@ __SPACE__
* [*Postconditions: ] `*this` is [_initialized]. * [*Postconditions: ] `*this` is [_initialized].
* [*Throws:] Whatever the selected `T`'s constructor throws. * [*Throws:] Whatever the selected `T`'s constructor throws.
* [*Exception Safety:] If an exception is thrown during the initialization of `T`, `*this` is ['uninitialized]. * [*Exception Safety:] If an exception is thrown during the initialization of `T`, `*this` is ['uninitialized].
* [*Notes:] `T` need not be __MOVE_CONSTRUCTIBLE__ or `MoveAssignable`. * [*Notes:] `T` need not be __MOVE_CONSTRUCTIBLE__ or `MoveAssignable`.
* [*Example:] * [*Example:]
`` ``
T v; T v;
@@ -524,7 +525,7 @@ factory.
* [*Postconditions: ] `*this` is [_initialized] and its value is ['directly given] * [*Postconditions: ] `*this` is [_initialized] and its value is ['directly given]
from the factory `f` (i.e., the value [_is not copied]). from the factory `f` (i.e., the value [_is not copied]).
* [*Throws:] Whatever the `T` constructor called by the factory throws. * [*Throws:] Whatever the `T` constructor called by the factory throws.
* [*Notes:] See [link boost_optional.design.in_place_factories In-Place Factories] * [*Notes:] See [link boost_optional_factories In-Place Factories]
* [*Exception Safety:] Exceptions can only be thrown during the call to * [*Exception Safety:] Exceptions can only be thrown during the call to
the `T` constructor used by the factory; in that case, the `optional` object the `T` constructor used by the factory; in that case, the `optional` object
will be reset to be ['uninitialized]. will be reset to be ['uninitialized].
@@ -540,15 +541,15 @@ __SPACE__
[#reference_optional_reset] [#reference_optional_reset]
[: `void optional<T>::reset() noexcept ;`] [: `constexpr void optional<T>::reset() noexcept ;`]
* [*Effects:] Same as `operator=( none_t );` * [*Effects:] Same as `operator=( none_t );`
__SPACE__ __SPACE__
[#reference_optional_get] [#reference_optional_get]
[: `T const& optional<T>::get() const ;`] [: `constexpr T const& optional<T>::get() const ;`]
[: `T& optional<T>::get() ;`] [: `constexpr T& optional<T>::get() ;`]
[: `inline T const& get ( optional<T> const& ) ;`] [: `inline T const& get ( optional<T> const& ) ;`]
[: `inline T& get ( optional<T> &) ;`] [: `inline T& get ( optional<T> &) ;`]
@@ -563,8 +564,8 @@ __SPACE__
[#reference_optional_operator_asterisk] [#reference_optional_operator_asterisk]
[: `T const& optional<T>::operator*() const& ;`] [: `constexpr T const& optional<T>::operator*() const& ;`]
[: `T& optional<T>::operator*() &;`] [: `constexpr T& optional<T>::operator*() &;`]
* [*Requires:] `*this` is initialized * [*Requires:] `*this` is initialized
* [*Returns:] A reference to the contained value * [*Returns:] A reference to the contained value
@@ -585,7 +586,7 @@ __SPACE__
[#reference_optional_operator_asterisk_move] [#reference_optional_operator_asterisk_move]
[: `T&& optional<T>::operator*() &&;`] [: `constexpr T&& optional<T>::operator*() &&;`]
* [*Requires:] `*this` contains a value. * [*Requires:] `*this` contains a value.
* [*Effects:] Equivalent to `return std::move(*val);`. * [*Effects:] Equivalent to `return std::move(*val);`.
@@ -596,8 +597,8 @@ __SPACE__
[#reference_optional_value] [#reference_optional_value]
[: `T const& optional<T>::value() const& ;`] [: `constexpr T const& optional<T>::value() const& ;`]
[: `T& optional<T>::value() & ;`] [: `constexpr T& optional<T>::value() & ;`]
* [*Effects:] Equivalent to `return bool(*this) ? *val : throw bad_optional_access();`. * [*Effects:] Equivalent to `return bool(*this) ? *val : throw bad_optional_access();`.
* [*Notes:] On compilers that do not support ref-qualifiers on member functions these two overloads are replaced with the classical two: a `const` and non-`const` member functions. * [*Notes:] On compilers that do not support ref-qualifiers on member functions these two overloads are replaced with the classical two: a `const` and non-`const` member functions.
@@ -620,7 +621,7 @@ __SPACE__
[#reference_optional_value_move] [#reference_optional_value_move]
[: `T&& optional<T>::value() && ;`] [: `constexpr T&& optional<T>::value() && ;`]
* [*Effects:] Equivalent to `return bool(*this) ? std::move(*val) : throw bad_optional_access();`. * [*Effects:] Equivalent to `return bool(*this) ? std::move(*val) : throw bad_optional_access();`.
* [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is not present. * [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is not present.
@@ -630,17 +631,25 @@ __SPACE__
[#reference_optional_value_or] [#reference_optional_value_or]
[: `template<class U> T optional<T>::value_or(U && v) const& ;`] [: `template<class U = T> constexpr T optional<T>::value_or(U && v) const& ;`]
* [*Effects:] Equivalent to `if (*this) return **this; else return std::forward<U>(v);`. * [*Effects:] Equivalent to `if (*this) return **this; else return std::forward<U>(v);`.
* [*Remarks:] If `T` is not __COPY_CONSTRUCTIBLE__ or `U &&` is not convertible to `T`, the program is ill-formed. * [*Remarks:] If `T` is not __COPY_CONSTRUCTIBLE__ or `U &&` is not convertible to `T`, the program is ill-formed.
* [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is replaced with the `const`-qualified member function. On compilers without rvalue reference support the type of `v` becomes `U const&`. * [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is replaced with the `const`-qualified member function. On compilers without rvalue reference support the type of `v` becomes `U const&`.
* [*Example:]
``
optional<int> oN, o1(1);
assert (o1.value_or(9) == 1);
assert (oN.value_or(9) == 9);
assert (oN.value_or({}) == 0);
``
__SPACE__ __SPACE__
[#reference_optional_value_or_move] [#reference_optional_value_or_move]
[: `template<class U> T optional<T>::value_or(U && v) && ;`] [: `template<class U> constexpr T optional<T>::value_or(U && v) && ;`]
* [*Effects:] Equivalent to `if (*this) return std::move(**this); else return std::forward<U>(v);`. * [*Effects:] Equivalent to `if (*this) return std::move(**this); else return std::forward<U>(v);`.
* [*Remarks:] If `T` is not __MOVE_CONSTRUCTIBLE__ or `U &&` is not convertible to `T`, the program is ill-formed. * [*Remarks:] If `T` is not __MOVE_CONSTRUCTIBLE__ or `U &&` is not convertible to `T`, the program is ill-formed.
@@ -650,7 +659,7 @@ __SPACE__
[#reference_optional_value_or_call] [#reference_optional_value_or_call]
[: `template<class F> T optional<T>::value_or_eval(F f) const& ;`] [: `template<class F> constexpr T optional<T>::value_or_eval(F f) const& ;`]
* [*Requires:] `T` is __COPY_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`. * [*Requires:] `T` is __COPY_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`.
* [*Effects:] `if (*this) return **this; else return f();`. * [*Effects:] `if (*this) return **this; else return f();`.
@@ -677,7 +686,7 @@ __SPACE__
[#reference_optional_value_or_call_move] [#reference_optional_value_or_call_move]
[: `template<class F> T optional<T>::value_or_eval(F f) && ;`] [: `template<class F> constexpr T optional<T>::value_or_eval(F f) && ;`]
* [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`. * [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`.
* [*Effects:] `if (*this) return std::move(**this); else return f();`. * [*Effects:] `if (*this) return std::move(**this); else return f();`.
@@ -687,8 +696,8 @@ __SPACE__
[#reference_optional_map] [#reference_optional_map]
[: `template<class F> auto optional<T>::map(F f) const& -> `['see below]` ;`] [: `template<class F> constexpr auto optional<T>::map(F f) const& -> `['see below]` ;`]
[: `template<class F> auto optional<T>::map(F f) & -> `['see below]` ;`] [: `template<class F> constexpr auto optional<T>::map(F f) & -> `['see below]` ;`]
* [*Effects:] `if (*this) return f(**this); else return none;` * [*Effects:] `if (*this) return f(**this); else return none;`
* [*Notes:] The return type of these overloads is `optional<decltype(f(**this))>`. On compilers that do not support ref-qualifiers on member functions, these two (as well as the next one) overloads are replaced with good old const and non-const overloads. * [*Notes:] The return type of these overloads is `optional<decltype(f(**this))>`. On compilers that do not support ref-qualifiers on member functions, these two (as well as the next one) overloads are replaced with good old const and non-const overloads.
@@ -706,7 +715,7 @@ __SPACE__
[#reference_optional_map_move] [#reference_optional_map_move]
[: `template<class F> auto optional<T>::map(F f) && -> `['see below]` ;`] [: `template<class F> constexpr auto optional<T>::map(F f) && -> `['see below]` ;`]
* [*Effects:] `if (*this) return f(std::move(**this)); else return none;` * [*Effects:] `if (*this) return f(std::move(**this)); else return none;`
* [*Notes:] The return type of this overload is `optional<decltype(f(istd::move(**this)))>`. * [*Notes:] The return type of this overload is `optional<decltype(f(istd::move(**this)))>`.
@@ -715,8 +724,8 @@ __SPACE__
[#reference_optional_flat_map] [#reference_optional_flat_map]
[: `template<class F> auto optional<T>::flat_map(F f) const& -> `['see below]` ;`] [: `template<class F> constexpr auto optional<T>::flat_map(F f) const& -> `['see below]` ;`]
[: `template<class F> auto optional<T>::flat_map(F f) & -> `['see below]` ;`] [: `template<class F> constexpr auto optional<T>::flat_map(F f) & -> `['see below]` ;`]
* [*Requires:] The return type of expression `f(**this)` is `optional<U>` for some object or reference type `U`. * [*Requires:] The return type of expression `f(**this)` is `optional<U>` for some object or reference type `U`.
* [*Effects:] `if (*this) return f(**this); else return none;` * [*Effects:] `if (*this) return f(**this); else return none;`
@@ -736,7 +745,7 @@ __SPACE__
[#reference_optional_flat_map_move] [#reference_optional_flat_map_move]
[: `template<class F> auto optional<T>::flat_map(F f) && -> `['see below]` ;`] [: `template<class F> constexpr auto optional<T>::flat_map(F f) && -> `['see below]` ;`]
* [*Requires:] The return type of expression `f(std::move(**this))` is `optional<U>` for some object or reference type `U`. * [*Requires:] The return type of expression `f(std::move(**this))` is `optional<U>` for some object or reference type `U`.
* [*Effects:] `if (*this) return f(std::move(**this)); else return none;` * [*Effects:] `if (*this) return f(std::move(**this)); else return none;`
@@ -744,6 +753,26 @@ __SPACE__
__SPACE__ __SPACE__
[#reference_optional_conversion_to_ref]
[: `constexpr optional<T>::operator optional<T&>() & noexcept ;`]
* [*Returns:] If `*this` contains a value `optional<T&>(**this)`, otherwise `optional<T&>()`.
[: `constexpr optional<T>::operator optional<T const&>() const& noexcept ;`]
* [*Returns:] If `*this` contains a value `optional<T const&>(**this)`, otherwise `optional<T&>()`.
* [*Example:]
``
const optional<int> oi = 1;
optional<const int&> ri = oi;
``
__SPACE__
[#reference_optional_get_value_or_value] [#reference_optional_get_value_or_value]
[: `T const& optional<T>::get_value_or( T const& default) const ;`] [: `T const& optional<T>::get_value_or( T const& default) const ;`]
@@ -793,8 +822,8 @@ __SPACE__
[#reference_optional_operator_arrow] [#reference_optional_operator_arrow]
[: `T const* optional<T>::operator ->() const ;`] [: `constexpr T const* optional<T>::operator ->() const ;`]
[: `T* optional<T>::operator ->() ;`] [: `constexpr T* optional<T>::operator ->() ;`]
* [*Requires: ] `*this` is initialized. * [*Requires: ] `*this` is initialized.
* [*Returns:] A pointer to the contained value. * [*Returns:] A pointer to the contained value.
@@ -812,44 +841,29 @@ __SPACE__
[#reference_optional_operator_bool] [#reference_optional_operator_bool]
[: `explicit optional<T>::operator bool() const noexcept ;`] [: `constexpr explicit optional<T>::operator bool() const noexcept ;`]
[: `bool optional<T>::has_value() const noexcept ;`] [: `constexpr bool optional<T>::has_value() const noexcept ;`]
* [*Returns:] `get_ptr() != 0`. * [*Returns:] `get_ptr() != 0`.
* [*Notes:] On compilers that do not support explicit conversion operators this falls back to safe-bool idiom. * [*Notes:] On compilers that do not support explicit conversion operators this falls back to safe-bool idiom.
* [*Example:] * [*Example:]
`` ``
optional<T> def ; optional<int> oN;
assert ( def == 0 ); assert (!oN);
optional<T> opt ( v ) ; assert (!oN.has_value());
assert ( opt );
assert ( opt != 0 ); optional<int> o1(1);
assert (o1);
assert (o1.has_value());
assert (!!o1); // the "double-bang" idiom
`` ``
__SPACE__ __SPACE__
[#reference_optional_operator_not]
[: `bool optional<T>::operator!() noexcept ;`]
* [*Returns:] If `*this` is uninitialized, `true`; else `false`.
* [*Notes:] This operator is provided for those compilers which can't
use the ['unspecified-bool-type operator] in certain boolean contexts.
* [*Example:]
``
optional<T> opt ;
assert ( !opt );
*opt = some_T ;
// Notice the "double-bang" idiom here.
assert ( !!opt ) ;
``
__SPACE__
[#reference_optional_is_initialized] [#reference_optional_is_initialized]
[: `bool optional<T>::is_initialized() const ;`] [: `constexpr bool optional<T>::is_initialized() const ;`]
* [*Deprecated:] Same as `explicit operator bool () ;` * [*Deprecated:] Same as `explicit operator bool () ;`
@@ -862,8 +876,8 @@ __SPACE__
[#reference_optional_ref_default_ctor] [#reference_optional_ref_default_ctor]
[: `optional<T&>::optional() noexcept;`] [: `constexpr optional<T&>::optional() noexcept;`]
[: `optional<T&>::optional(none_t) noexcept;`] [: `constexpr optional<T&>::optional(none_t) noexcept;`]
* [*Postconditions:] `bool(*this) == false`; `*this` refers to nothing. * [*Postconditions:] `bool(*this) == false`; `*this` refers to nothing.
@@ -963,7 +977,7 @@ __SPACE__
* [*Postconditions:] `bool(*this) == bool(rhs)`. * [*Postconditions:] `bool(*this) == bool(rhs)`.
* [*Notes:] This behaviour is called ['rebinding semantics]. See [link boost_optional.design.optional_references.rebinding_semantics_for_assignment_of_optional_references here] for details. * [*Notes:] This behaviour is called ['rebinding semantics]. See [link optional_ref_rebinding_semantics here] for details.
* [*Example:] * [*Example:]
`` ``
+1 -1
View File
@@ -11,7 +11,7 @@
[section Header <boost/optional.hpp>] [section Header <boost/optional.hpp>]
This is an alias for header [link boost_optional.reference.header__boost_optional_optional_hpp_.header_optional_optional `<boost/optional/optional.hpp>`]. This is an alias for header [link ref_header_optional_optional_hpp `<boost/optional/optional.hpp>`].
[endsect] [endsect]
+56 -2
View File
@@ -9,7 +9,62 @@
] ]
[section Dependencies and Portability] [section Dependencies and Portability][#minimum_system_requirements]
[section Minimum System Requirements]
This library requires C++11 as minimum. However, in C++11 some features are disabled.
[section:constexpr Support for `constexpr`]
[section C++11]
For compilers fully supporting C++11 (including unconstrained unions and ref-qualifiers),
for trivially-destructible `T`s, `optional<T>` is a ['literal type] and its constructors
with `this->has_value() == false` as postcondition:
* `optional()`,
* `optional(none_t)`,
are ['core constant expressions]. Even for other `T`s, these constructors are guaranteed to
perform ['constant initialization]: they are never subject to "initialization order fiasco".
Other constructors with `this->has_value() == true`
as postcondition are core constant expressions if the expression required to initialize
the contained value is a core constant expression. This includes constructors:
* `template <typename... Args> optional(in_place_init, Args&&...)`,
* `template <typename U> optional(U&&)`,
* `optional(const T&)`,
* `optional(T&&)`.
Other constructors, including the copy and move constructos, are ['not] core constant expressions.
Member functions `.has_value`, `operator bool` and (non)equality comparisons with `none` are core-constant expressions for trivially-destructible `T`s.
Also all `const`-qualified non-static member functions and comparison operators are core constant expressions, if the corresponding operations on `T`
are core constant expressions.
[endsect]
[section C++14]
For C++14 and higher this library, for trivially-destructible `T`s provides the `constexpr` interface for all mutable and non-mutable
member functions, as long as:
* the corresponding operations on `T` are core constant expressions and
* the member never attempts to change the `optional`'s state from not containing a value to containing a value.
[note For types that overload unary `operator&` (address) some member functions in `optional`, like `operator->`,
cannot be implemented as `constexpr` on some compilers.]
[endsect]
[section C++17]
In C++17 all non-deprecated constructors are core constant expressions as long as
`T` is a literal type and its constructor used is a core constant expression.
[endsect]
[endsect:constexpr]
[endsect]
[section Dependencies] [section Dependencies]
The implementation uses the following other Boost modules: The implementation uses the following other Boost modules:
@@ -17,7 +72,6 @@ The implementation uses the following other Boost modules:
# assert # assert
# config # config
# core # core
# static_assert
# throw_exception # throw_exception
# type_traits # type_traits
+18 -3
View File
@@ -11,8 +11,7 @@
[section:std_comp Comparison with `std::optional`] [section:std_comp Comparison with `std::optional`]
[table [table Comparison with `std::optional`
[]
[ [[*`boost::optional`]] [[*`std::optional`]] [] ] [ [[*`boost::optional`]] [[*`std::optional`]] [] ]
[ [`optional<int> o = none;`] [`optional<int> o = nullopt;`] [Different name for no-value tag.] ] [ [`optional<int> o = none;`] [`optional<int> o = nullopt;`] [Different name for no-value tag.] ]
[ [`optional<X> o {in_place_init, a, b};`] [`optional<int> o {in_place, a, b};`] [Different name for in-place initialization tag.] ] [ [`optional<X> o {in_place_init, a, b};`] [`optional<int> o {in_place, a, b};`] [Different name for in-place initialization tag.] ]
@@ -42,7 +41,23 @@
[ [`make_optional(cond, v);`] [] [No `make_optional` with condition in `std`.] ] [ [`make_optional(cond, v);`] [] [No `make_optional` with condition in `std`.] ]
[ [] [`make_optional<T>(a, b);`] [No `make_optional` with specified `T` in `boost`.] ] [ [] [`make_optional<T>(a, b);`] [No `make_optional` with specified `T` in `boost`.] ]
[ [`std::cout << optional<int>{};`] [] [No printing to IOStreams in `std`.]] [ [`std::cout << optional<int>{};`] [] [No printing to IOStreams in `std`.]]
[ [`std::vector<optional<int>> rng;`
`std::ranges::find(rng, boost::none)`] [`std::vector<optional<int>> rng;`
`std::ranges::find(rng, boost::optional<int>{})`] [optional<T> is never [@https://en.cppreference.com/w/cpp/concepts/equality_comparable `std::equality_comparable_with`] `nullopt_t` in `std`. ] ]
[ [```
void test(vector<optional<T>> rng, T val) {
std::ranges::find(rng, val);
}
```] [```
void test(vector<optional<T>> rng, T val) {
std::ranges::find(rng, make_optional(val));
}
```] [For `std::optional`, code without `make_optional()` compiles but is ['undefined behavior] when `T` is itself an `optional`. ] ]
] ]
[endsect][/ std_comp] [endsect][/ std_comp]
+57 -2
View File
@@ -1,7 +1,7 @@
[/ [/
Boost.Optional Boost.Optional
Copyright (c) 2015 - 2023 Andrzej Krzemienski Copyright (c) 2015 - 2026 Andrzej Krzemienski
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
@@ -11,6 +11,61 @@
[section:relnotes Release Notes] [section:relnotes Release Notes]
[heading Boost Release 1.xx]
* Fixed regression in the copy-initialization of `optional<bool>`. This fixes [@https://github.com/boostorg/optional/issues/146 issue #146].
[heading Boost Release 1.91]
* For compilers with full C++11 support (including "unrestricted unions" and ref-qualifiers)
changed the implementation from aligned storage to union storage. This enables the gradual
`constexpr` support:
* In C++11, some constructors and `const`-qualified accessors become usable
in compile-time contexts (are ['core constant expressions]) for types
satisfying certain constraints.
* In C++14 even some mutating operations become core constant expressions (those
that do not require changing the state of `optional` from not having a value to
having a value), for co-operating types.
* In C++17 all constructors (including copy and move) become core constant expressions
for co-operating types.
This addresses issues [@https://github.com/boostorg/optional/issues/132 #132] and [@https://github.com/boostorg/optional/issues/143 #143].
* *Breaking change.* In the said implementation, abandoned the mechanism for customizing
`swap`. Hardly anyone knows about this mechanism and it was never documented.
* In the said implementation, applied a couple of small changes to get closer to the interface of `std::optional`:
* Enabled syntax `o = {}` for putting optional objects to no-value state.
* Enabled syntax `o.value_or({})`, which uses a default-constructed `T`.
* Construct `o = u`, where `o` is of type `optional<T>` and `u` is of type `U` convertible to `T`,
does not create a temporary `T`.
* In the said implementation, added a conversion from `optional<T>&` to `optional<T&>`. This addresses [@https://github.com/boostorg/optional/issues/142 issue #142].
* `none_t` is now `std::equality_comparable`, which means that `none_t` and `optional<T>`
model concept `std::equality_comparable_with` (for `std::equality_comparable` `T`s),
which means that you can `std::ranges::find(rng, boost::none)` for a range of optional objects.
* *Warning.* In the future releases we intend to introduce the range interface
in `optional`, so that `std::ranges::range<optional<T>>` will be `true`.
This may affect the overload resolution in programs that make decisions based
on predicates such as `std::ranges::range`. For instance, the following code
will start behaving differently:
```
template <typename T>
void serialize(T const& v)
{
if constexpr (std::ranges::range<T>)
serialize_as_range(v);
else if constexpr (custom::is_optional_like<T>)
serialize_as_optional(v);
else
serialize_as_value(v);
}
```
[heading Boost Release 1.87] [heading Boost Release 1.87]
* *Breaking change.* Dropped support for C++03. C++11 is now the required minimum; at least some C++11 features. * *Breaking change.* Dropped support for C++03. C++11 is now the required minimum; at least some C++11 features.
@@ -22,7 +77,7 @@
* *Warning.* In the future releases we intend to introduce the range interface * *Warning.* In the future releases we intend to introduce the range interface
into `optional`, so that `std::ranges::range<optional<T>>` will be `true`. into `optional`, so that `std::ranges::range<optional<T>>` will be `true`.
This may affect the overload resolution in programs that make decisions based This may affect the overload resolution in programs that make decisions based
on predicates such as `std::ranges::range`. on predicates such as `std::ranges::range`.
* Tags `in_place_init` and `in_place_init_if` become `inline constexpr` and therewith leave smaller footprint in the executable. This addresses [@https://github.com/boostorg/optional/issues/103 issue #103]. * Tags `in_place_init` and `in_place_init_if` become `inline constexpr` and therewith leave smaller footprint in the executable. This addresses [@https://github.com/boostorg/optional/issues/103 issue #103].
+6 -1
View File
@@ -25,7 +25,7 @@
#elif defined(BOOST_NO_CXX11_REF_QUALIFIERS) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DEFAULTED_MOVES) #elif defined(BOOST_NO_CXX11_REF_QUALIFIERS) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Optional 1.83 and will be removed in Boost.Optional 1.88.") BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Optional 1.83 and will be removed in Boost.Optional 1.92.")
#endif #endif
@@ -46,6 +46,11 @@ struct none_t
{ {
struct init_tag{}; struct init_tag{};
explicit BOOST_CONSTEXPR none_t(init_tag){} // to disable default constructor explicit BOOST_CONSTEXPR none_t(init_tag){} // to disable default constructor
#ifndef BOOST_OPTIONAL_DISABLE_EQUALITY_FOR_NONE
friend BOOST_CONSTEXPR bool operator==(none_t, none_t) { return true; }
friend BOOST_CONSTEXPR bool operator!=(none_t, none_t) { return false; }
#endif
}; };
#endif // old implementation workarounds #endif // old implementation workarounds
@@ -0,0 +1,188 @@
// Copyright (C) 2024 Ryan Malcolm Underwood.
// Copyright (C) 2026 Andrzej Krzemieński.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/optional for documentation.
//
// You are welcome to contact the authors at:
// akrzemi1@gmail.com
// typenametea@gmail.com
//
//
// This header provides definitions required by any specialization of
// optional<>.
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_COMMON_DEFS_01FEB2026_HPP
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_COMMON_DEFS_01FEB2026_HPP
#include <boost/config.hpp>
#include <boost/core/addressof.hpp>
#include <type_traits>
#include <boost/optional/detail/optional_factory_support.hpp>
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#include <boost/type_traits/decay.hpp>
#include <boost/type_traits/is_base_of.hpp>
#endif
// This is needed for C++11, where constexpr functions must contain a single expression.
// We want to assert and then return.
#if defined NDEBUG
# define BOOST_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
#else
# define BOOST_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{BOOST_ASSERT(!(#CHECK));}(), (EXPR)))
#endif
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
# define BOOST_OPTIONAL_DECAY(T) typename ::std::decay<T>::type
# define BOOST_OPTIONAL_IS_TAGGED(TAG, U) ::std::is_base_of<TAG, BOOST_OPTIONAL_DECAY(U)>
#else
# define BOOST_OPTIONAL_DECAY(T) BOOST_DEDUCED_TYPENAME boost::decay<T>::type
# define BOOST_OPTIONAL_IS_TAGGED(TAG, U) boost::is_base_of<TAG, BOOST_OPTIONAL_DECAY(U)>
#endif
namespace boost {
template <typename T> class optional;
// Boost-wide tags for recognizing "factories": a C++03 workaround
// for perfect forwarding.
class in_place_factory_base;
class typed_in_place_factory_base;
} // namespace boost
// Traits for recognizing in-place factories
namespace boost { namespace optional_detail {
template <typename U>
struct is_in_place_factory : BOOST_OPTIONAL_IS_TAGGED(boost::in_place_factory_base, U) {};
template <typename U>
struct is_typed_in_place_factory : BOOST_OPTIONAL_IS_TAGGED(boost::typed_in_place_factory_base, U) {};
}}
/** This is a set of declarations that repeat those from the Standard Library
header <utility> but without having to drag its entire content. They also
add missing capabilities, like constexpr, in older compiler versions.
*/
namespace boost { namespace optional_detail {
template <typename T>
T declval_();
template <class T>
inline constexpr T&& forward_(typename ::std::remove_reference<T>::type& t) noexcept
{
return static_cast<T&&>(t);
}
template <class T>
inline constexpr T&& forward_(typename ::std::remove_reference<T>::type&& t) noexcept
{
static_assert(!::std::is_lvalue_reference<T>::value, "Can not forward an rvalue as an lvalue.");
return static_cast<T&&>(t);
}
template <class T>
inline constexpr typename ::std::remove_reference<T>::type&& move_(T&& t) noexcept
{
return static_cast<typename ::std::remove_reference<T>::type&&>(t);
}
}} // namespace boost::optional_detail
/** This is a set of declarations that are not part of this library's interface.
They are implementation details.
*/
namespace boost { namespace optional_detail {
/** This struct is used for tagging types that want to be recognized as
`optional`. If your class inherits directly or indirectly from `optional_tag`
the type traits and overloads will treat it as `optional<>`.
*/
struct optional_tag {};
/** `optional_value_type`: given type `X`:
* if `X` is an instance of `boost::optional`, returns its value_type,
* otherwise we get a SFINAE-able error.
*/
template <typename X>
struct optional_value_type
{
};
template <typename U>
struct optional_value_type< ::boost::optional<U> >
{
typedef U type;
};
/** This is an approximation of a 1-argument C++17 std::invoke_result.
*/
template <typename F, typename Ref, typename Rslt = decltype(declval_<F>()(declval_<Ref>()))>
struct result_of
{
typedef Rslt type;
};
/** This type trait returns the following given the expression `f(ref)`:
* if the result is a specialization of `boost::optional`: its value_type,
* otherwise a SFINAE-able error.
*/
template <typename F, typename Ref, typename Rslt = typename optional_value_type<typename result_of<F, Ref>::type>::type>
struct result_value_type
{
typedef Rslt type;
};
}} // namespace boost::optional_detail
/** The following two tags are intended to be used by library users.
The additional namespace is used in order to prevent the ADL from
dragging all functions from namespace `boost` in any unqualified name lookup
when these tags are involved.
*/
namespace boost {
namespace optional_ns {
/// a tag for in-place initialization of contained value
struct in_place_init_t
{
struct init_tag{};
BOOST_CONSTEXPR explicit in_place_init_t(init_tag){}
};
BOOST_INLINE_CONSTEXPR in_place_init_t in_place_init ((in_place_init_t::init_tag()));
/// a tag for conditional in-place initialization of contained value
struct in_place_init_if_t
{
struct init_tag{};
BOOST_CONSTEXPR explicit in_place_init_if_t(init_tag){}
};
BOOST_INLINE_CONSTEXPR in_place_init_if_t in_place_init_if ((in_place_init_if_t::init_tag()));
} // namespace optional_ns
using optional_ns::in_place_init_t;
using optional_ns::in_place_init;
using optional_ns::in_place_init_if_t;
using optional_ns::in_place_init_if;
} // namespace boost
#endif // BOOST_OPTIONAL_DETAIL_OPTIONAL_COMMON_DEFS_01FEB2026_HPP
@@ -27,10 +27,4 @@ namespace boost_optional_detail
} }
} }
namespace boost
{
class in_place_factory_base ;
class typed_in_place_factory_base ;
}
#endif // header guard #endif // header guard
@@ -12,7 +12,7 @@
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_HASH_AJK_20MAY2022_HPP #ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_HASH_AJK_20MAY2022_HPP
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_HASH_AJK_20MAY2022_HPP #define BOOST_OPTIONAL_DETAIL_OPTIONAL_HASH_AJK_20MAY2022_HPP
#include <boost/optional/optional_fwd.hpp> //#include <boost/optional/optional_fwd.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#if !defined(BOOST_OPTIONAL_CONFIG_DO_NOT_SPECIALIZE_STD_HASH) && !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) #if !defined(BOOST_OPTIONAL_CONFIG_DO_NOT_SPECIALIZE_STD_HASH) && !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL)
@@ -0,0 +1,117 @@
// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
// Copyright (C) 2014 - 2026 Andrzej Krzemieński.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/optional for documentation.
//
// You are welcome to contact the authors at:
// fernando_cacciola@hotmail.com
// akrzemi1@gmail.com
//
// You can file a GitHub issue at:
// https://github.com/boostorg/optional/issues
// This header provides definitions rof nonmember functions that still constitute
// the interface for class optional<>.
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_NONMEMBER_INTERFACE_01FEB2026_HPP
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_NONMEMBER_INTERFACE_01FEB2026_HPP
namespace boost {
template <class T>
inline BOOST_CXX14_CONSTEXPR
optional<BOOST_OPTIONAL_DECAY(T)> make_optional ( T && v )
{
return optional<BOOST_OPTIONAL_DECAY(T)>(optional_detail::forward_<T>(v));
}
// Returns optional<T>(cond,v)
template <class T>
inline BOOST_CXX14_CONSTEXPR
optional<BOOST_OPTIONAL_DECAY(T)> make_optional ( bool cond, T && v )
{
return optional<BOOST_OPTIONAL_DECAY(T)>(cond,optional_detail::forward_<T>(v));
}
// Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
// No-throw
template <class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
get ( optional<T> const& opt )
{
return opt.get() ;
}
template <class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::reference_type
get ( optional<T>& opt )
{
return opt.get() ;
}
// Returns a pointer to the value if this is initialized, otherwise, returns NULL.
// No-throw
template<class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
get ( optional<T> const* opt )
{
return opt->get_ptr() ;
}
template<class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
get ( optional<T>* opt )
{
return opt->get_ptr() ;
}
// Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
// No-throw
template<class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
get_optional_value_or ( optional<T> const& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type v )
{
return opt.get_value_or(v) ;
}
template<class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::reference_type
get_optional_value_or ( optional<T>& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_type v )
{
return opt.get_value_or(v) ;
}
// Returns a pointer to the value if this is initialized, otherwise, returns NULL.
// No-throw
template<class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
get_pointer ( optional<T> const& opt )
{
return opt.get_ptr() ;
}
template<class T>
inline BOOST_CXX14_CONSTEXPR
BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
get_pointer ( optional<T>& opt )
{
return opt.get_ptr() ;
}
} // namespace boost
#endif // BOOST_OPTIONAL_DETAIL_OPTIONAL_NONMEMBER_INTERFACE_01FEB2026_HPP
@@ -13,9 +13,21 @@
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_REFERENCE_SPEC_AJK_03OCT2015_HPP #define BOOST_OPTIONAL_DETAIL_OPTIONAL_REFERENCE_SPEC_AJK_03OCT2015_HPP
#ifdef BOOST_OPTIONAL_CONFIG_NO_PROPER_ASSIGN_FROM_CONST_INT #ifdef BOOST_OPTIONAL_CONFIG_NO_PROPER_ASSIGN_FROM_CONST_INT
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#include <boost/type_traits/is_integral.hpp> #include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_const.hpp> #include <boost/type_traits/is_const.hpp>
#endif #endif
#endif
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
# define BOOST_OPTIONAL_TT_PREFIX ::std
#else
# define BOOST_OPTIONAL_TT_PREFIX boost
# define BOOST_OPTIONAL_REQUIRES(...) BOOST_DEDUCED_TYPENAME boost::enable_if_c<__VA_ARGS__::value, bool>::type = false
#endif
# define BOOST_OPTIONAL_TT_TYPE(...) BOOST_DEDUCED_TYPENAME BOOST_OPTIONAL_TT_PREFIX::__VA_ARGS__::type
# define BOOST_OPTIONAL_TT_PRED(...) BOOST_OPTIONAL_TT_PREFIX::__VA_ARGS__::value
# if 1 # if 1
@@ -29,17 +41,17 @@ template <class From>
void prevent_binding_rvalue() void prevent_binding_rvalue()
{ {
#ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES #ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES
static_assert(boost::is_lvalue_reference<From>::value, static_assert(BOOST_OPTIONAL_TT_PRED(is_lvalue_reference<From>),
"binding rvalue references to optional lvalue references is disallowed"); "binding rvalue references to optional lvalue references is disallowed");
#endif #endif
} }
template <class T> template <class T>
BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type& forward_reference(T&& r) BOOST_OPTIONAL_TT_TYPE(remove_reference<T>)& forward_reference(T&& r)
{ {
static_assert(boost::is_lvalue_reference<T>::value, static_assert(BOOST_OPTIONAL_TT_PRED(is_lvalue_reference<T>),
"binding rvalue references to optional lvalue references is disallowed"); "binding rvalue references to optional lvalue references is disallowed");
return optional_detail::forward<T>(r); return optional_detail::forward_<T>(r);
} }
#endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
@@ -48,14 +60,14 @@ BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type& forward_reference(T&& r
template <class T> template <class T>
struct is_const_integral struct is_const_integral
{ {
static const bool value = boost::is_const<T>::value && boost::is_integral<T>::value; static const bool value = BOOST_OPTIONAL_TT_PRED(is_const<T>) && BOOST_OPTIONAL_TT_PRED(is_integral<T>);
}; };
template <class T> template <class T>
struct is_const_integral_bad_for_conversion struct is_const_integral_bad_for_conversion
{ {
#if (!defined BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES) && (defined BOOST_OPTIONAL_CONFIG_NO_PROPER_CONVERT_FROM_CONST_INT) #if (!defined BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES) && (defined BOOST_OPTIONAL_CONFIG_NO_PROPER_CONVERT_FROM_CONST_INT)
static const bool value = boost::is_const<T>::value && boost::is_integral<T>::value; static const bool value = is_const_integral<T>::value;
#else #else
static const bool value = false; static const bool value = false;
#endif #endif
@@ -90,15 +102,15 @@ struct is_optional_< ::boost::optional<U> >
template <class T> template <class T>
struct is_no_optional struct is_no_optional
{ {
static const bool value = !is_optional_<BOOST_DEDUCED_TYPENAME boost::decay<T>::type>::value; static const bool value = !is_optional_<BOOST_OPTIONAL_DECAY(T)>::value;
}; };
template <class T, class U> template <class T, class U>
struct is_same_decayed struct is_same_decayed
{ {
static const bool value = ::boost::is_same<T, BOOST_DEDUCED_TYPENAME ::boost::remove_reference<U>::type>::value static const bool value = BOOST_OPTIONAL_TT_PRED(is_same<T, BOOST_OPTIONAL_TT_TYPE(remove_reference<U>)>)
|| ::boost::is_same<T, const BOOST_DEDUCED_TYPENAME ::boost::remove_reference<U>::type>::value; || BOOST_OPTIONAL_TT_PRED(is_same<T, const BOOST_OPTIONAL_TT_TYPE(remove_reference<U>)>);
}; };
template <class T, class U> template <class T, class U>
@@ -123,152 +135,165 @@ public:
typedef T* pointer_type; typedef T* pointer_type;
typedef T* pointer_const_type; typedef T* pointer_const_type;
optional() BOOST_NOEXCEPT : ptr_() {} BOOST_CONSTEXPR optional() BOOST_NOEXCEPT : ptr_() {}
optional(none_t) BOOST_NOEXCEPT : ptr_() {} BOOST_CONSTEXPR optional(none_t) BOOST_NOEXCEPT : ptr_() {}
template <class U> template <class U>
explicit optional(const optional<U&>& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {} BOOST_CONSTEXPR explicit optional(const optional<U&>& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {}
optional(const optional& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {} BOOST_CONSTEXPR optional(const optional& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {}
// the following two implement a 'conditionally explicit' constructor: condition is a hack for buggy compilers with screwed conversion construction from const int // the following two implement a 'conditionally explicit' constructor: condition is a hack for buggy compilers with screwed conversion construction from const int
template <class U,
BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>),
BOOST_OPTIONAL_REQUIRES(detail::is_const_integral_bad_for_conversion<U>)>
BOOST_CONSTEXPR explicit
optional(U& rhs) BOOST_NOEXCEPT
: ptr_(boost::addressof(rhs)) {}
template <class U,
BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>),
BOOST_OPTIONAL_REQUIRES(!detail::is_const_integral_bad_for_conversion<U>)>
BOOST_CONSTEXPR
optional(U& rhs) BOOST_NOEXCEPT
: ptr_(boost::addressof(rhs)) {}
BOOST_CXX14_CONSTEXPR optional& operator=(const optional& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
template <class U> template <class U>
explicit optional(U& rhs, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::is_same_decayed<T, U>::value && detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR optional& operator=(const optional<U&>& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
: ptr_(boost::addressof(rhs)) {} BOOST_CXX14_CONSTEXPR optional& operator=(none_t) BOOST_NOEXCEPT { ptr_ = 0; return *this; }
template <class U>
optional(U& rhs, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::is_same_decayed<T, U>::value && !detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT
: ptr_(boost::addressof(rhs)) {}
optional& operator=(const optional& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
template <class U>
optional& operator=(const optional<U&>& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
optional& operator=(none_t) BOOST_NOEXCEPT { ptr_ = 0; return *this; }
void swap(optional& rhs) BOOST_NOEXCEPT { std::swap(ptr_, rhs.ptr_); } BOOST_CXX14_CONSTEXPR void swap(optional& rhs) BOOST_NOEXCEPT { ::std::swap(ptr_, rhs.ptr_); }
T& get() const { BOOST_ASSERT(ptr_); return *ptr_; } constexpr T& get() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, *ptr_); }
T* get_ptr() const BOOST_NOEXCEPT { return ptr_; } constexpr T* get_ptr() const BOOST_NOEXCEPT { return ptr_; }
T* operator->() const { BOOST_ASSERT(ptr_); return ptr_; } constexpr T* operator->() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, ptr_); }
T& operator*() const { BOOST_ASSERT(ptr_); return *ptr_; } constexpr T& operator*() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, *ptr_); }
T& value() const constexpr T& value() const
{ {
if (this->is_initialized()) return this->is_initialized() ?
return this->get(); this->get() :
else (boost::throw_exception(boost::bad_optional_access()), this->get());
throw_exception(bad_optional_access());
} }
explicit operator bool() const BOOST_NOEXCEPT { return ptr_ != 0; } constexpr explicit operator bool() const BOOST_NOEXCEPT { return ptr_ != 0; }
void reset() BOOST_NOEXCEPT { ptr_ = 0; } BOOST_CXX14_CONSTEXPR void reset() BOOST_NOEXCEPT { ptr_ = 0; }
bool is_initialized() const BOOST_NOEXCEPT { return ptr_ != 0; } constexpr bool is_initialized() const BOOST_NOEXCEPT { return ptr_ != 0; }
bool has_value() const BOOST_NOEXCEPT { return ptr_ != 0; } constexpr bool has_value() const BOOST_NOEXCEPT { return ptr_ != 0; }
template <typename F> template <typename F>
optional<typename optional_detail::result_of<F, reference_const_type>::type> constexpr optional<typename optional_detail::result_of<F, reference_const_type>::type>
map(F f) const map(F f) const
{ {
if (this->has_value()) return this->has_value() ?
return f(this->get()); f(get()) :
else optional<typename optional_detail::result_of<F, reference_const_type>::type>();
return none;
} }
template <typename F> template <typename F>
optional<typename optional_detail::result_value_type<F, reference_const_type>::type> constexpr optional<typename optional_detail::result_value_type<F, reference_const_type>::type>
flat_map(F f) const flat_map(F f) const
{ {
if (this->has_value()) return this->has_value() ?
return f(get()); f(get()) :
else optional<typename optional_detail::result_value_type<F, reference_const_type>::type>();
return none;
} }
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
optional(T&& /* rhs */) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<T&&>(); } optional(T&& /* rhs */) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<T&&>(); }
template <class R> template <class R, BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, R>)>
optional(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::no_unboxing_cond<T, R>, bool>::type = true) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR optional(R&& r) BOOST_NOEXCEPT
: ptr_(boost::addressof(r)) { detail::prevent_binding_rvalue<R>(); } : ptr_(boost::addressof(r)) { detail::prevent_binding_rvalue<R>(); }
template <class R> template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
optional(bool cond, R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR optional(bool cond, R&& r) BOOST_NOEXCEPT
: ptr_(cond ? boost::addressof(r) : 0) { detail::prevent_binding_rvalue<R>(); } : ptr_(cond ? boost::addressof(r) : 0) { detail::prevent_binding_rvalue<R>(); }
template <class R> template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, optional<T&>&>::type BOOST_CXX14_CONSTEXPR optional<T&>&
operator=(R&& r) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); return *this; } operator=(R&& r) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); return *this; }
template <class R> template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
void emplace(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR void emplace(R&& r) BOOST_NOEXCEPT
{ detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); } { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); }
template <class R> template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
T& get_value_or(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) const BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR T& get_value_or(R&& r) const BOOST_NOEXCEPT
{ detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; } { detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; }
template <class R> template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
T& value_or(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) const BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR T& value_or(R&& r) const BOOST_NOEXCEPT
{ detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; } { detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; }
template <class R> template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
void reset(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR void reset(R&& r) BOOST_NOEXCEPT
{ detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); } { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); }
template <class F> template <class F>
T& value_or_eval(F f) const { return ptr_ ? *ptr_ : detail::forward_reference(f()); } BOOST_CXX14_CONSTEXPR T& value_or_eval(F f) const { return ptr_ ? *ptr_ : detail::forward_reference(f()); }
#else // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #else // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// the following two implement a 'conditionally explicit' constructor // the following two implement a 'conditionally explicit' constructor
template <class U> template <class U,
explicit optional(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::no_unboxing_cond<T, U>::value && detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, U>),
BOOST_OPTIONAL_REQUIRES(detail::is_const_integral_bad_for_conversion<U>)>
BOOST_CXX14_CONSTEXPR explicit optional(U& v) BOOST_NOEXCEPT
: ptr_(boost::addressof(v)) { } : ptr_(boost::addressof(v)) { }
template <class U> template <class U,
optional(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::no_unboxing_cond<T, U>::value && !detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, U>),
BOOST_OPTIONAL_REQUIRES(!detail::is_const_integral_bad_for_conversion<U>)>
BOOST_CXX14_CONSTEXPR optional(U& v) BOOST_NOEXCEPT
: ptr_(boost::addressof(v)) { } : ptr_(boost::addressof(v)) { }
template <class U> template <class U,
optional(bool cond, U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT : ptr_(cond ? boost::addressof(v) : 0) {} BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
BOOST_CXX14_CONSTEXPR optional(bool cond, U& v) BOOST_NOEXCEPT : ptr_(cond ? boost::addressof(v) : 0) {}
template <class U> template <class U,
BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, optional<T&>&>::type BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
operator=(U& v) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR
optional<T&>& operator=(U& v) BOOST_NOEXCEPT
{ {
detail::prevent_assignment_from_false_const_integral<U>(); detail::prevent_assignment_from_false_const_integral<U>();
ptr_ = boost::addressof(v); return *this; ptr_ = boost::addressof(v); return *this;
} }
template <class U> template <class U,
void emplace(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
BOOST_CXX14_CONSTEXPR void emplace(U& v) BOOST_NOEXCEPT
{ ptr_ = boost::addressof(v); } { ptr_ = boost::addressof(v); }
template <class U> template <class U,
T& get_value_or(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) const BOOST_NOEXCEPT BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
BOOST_CXX14_CONSTEXPR T& get_value_or(U& v) const BOOST_NOEXCEPT
{ return ptr_ ? *ptr_ : v; } { return ptr_ ? *ptr_ : v; }
template <class U> template <class U,
T& value_or(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) const BOOST_NOEXCEPT BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
{ return ptr_ ? *ptr_ : v; } BOOST_CXX14_CONSTEXPR T& value_or(U& v) const BOOST_NOEXCEPT
{ return ptr_ ? *ptr_ : v; }
template <class U> template <class U,
void reset(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
BOOST_CXX14_CONSTEXPR void reset(U& v) BOOST_NOEXCEPT
{ ptr_ = boost::addressof(v); } { ptr_ = boost::addressof(v); }
template <class F> template <class F>
T& value_or_eval(F f) const { return ptr_ ? *ptr_ : f(); } BOOST_CXX14_CONSTEXPR T& value_or_eval(F f) const { return ptr_ ? *ptr_ : f(); }
#endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
}; };
template <class T> template <class T>
void swap ( optional<T&>& x, optional<T&>& y) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR void swap ( optional<T&>& x, optional<T&>& y) BOOST_NOEXCEPT
{ {
x.swap(y); x.swap(y);
} }
@@ -1,5 +1,5 @@
// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
// Copyright (C) 2015, 2024 Andrzej Krzemienski. // Copyright (C) 2015, 2024, 2026 Andrzej Krzemienski.
// //
// Use, modification, and distribution is subject to the Boost Software // Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -25,32 +25,32 @@ namespace boost {
// //
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator == ( optional<T> const& x, optional<T> const& y ) bool operator == ( optional<T> const& x, optional<T> const& y )
{ return bool(x) && bool(y) ? *x == *y : bool(x) == bool(y); } { return bool(x) && bool(y) ? *x == *y : bool(x) == bool(y); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator < ( optional<T> const& x, optional<T> const& y ) bool operator < ( optional<T> const& x, optional<T> const& y )
{ return !y ? false : (!x ? true : (*x) < (*y)); } { return !y ? false : (!x ? true : (*x) < (*y)); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator != ( optional<T> const& x, optional<T> const& y ) bool operator != ( optional<T> const& x, optional<T> const& y )
{ return !( x == y ) ; } { return !( x == y ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator > ( optional<T> const& x, optional<T> const& y ) bool operator > ( optional<T> const& x, optional<T> const& y )
{ return y < x ; } { return y < x ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator <= ( optional<T> const& x, optional<T> const& y ) bool operator <= ( optional<T> const& x, optional<T> const& y )
{ return !( y < x ) ; } { return !( y < x ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator >= ( optional<T> const& x, optional<T> const& y ) bool operator >= ( optional<T> const& x, optional<T> const& y )
{ return !( x < y ) ; } { return !( x < y ) ; }
@@ -59,32 +59,32 @@ bool operator >= ( optional<T> const& x, optional<T> const& y )
// optional<T> vs T cases // optional<T> vs T cases
// //
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator == ( optional<T> const& x, T const& y ) bool operator == ( optional<T> const& x, T const& y )
{ return x && (*x == y); } { return x && (*x == y); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator < ( optional<T> const& x, T const& y ) bool operator < ( optional<T> const& x, T const& y )
{ return (!x) || (*x < y); } { return (!x) || (*x < y); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator != ( optional<T> const& x, T const& y ) bool operator != ( optional<T> const& x, T const& y )
{ return !( x == y ) ; } { return !( x == y ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator > ( optional<T> const& x, T const& y ) bool operator > ( optional<T> const& x, T const& y )
{ return y < x ; } { return y < x ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator <= ( optional<T> const& x, T const& y ) bool operator <= ( optional<T> const& x, T const& y )
{ return !( y < x ) ; } { return !( y < x ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator >= ( optional<T> const& x, T const& y ) bool operator >= ( optional<T> const& x, T const& y )
{ return !( x < y ) ; } { return !( x < y ) ; }
@@ -93,32 +93,32 @@ bool operator >= ( optional<T> const& x, T const& y )
// //
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator == ( T const& x, optional<T> const& y ) bool operator == ( T const& x, optional<T> const& y )
{ return y && (x == *y); } { return y && (x == *y); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator < ( T const& x, optional<T> const& y ) bool operator < ( T const& x, optional<T> const& y )
{ return y && (x < *y); } { return y && (x < *y); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator != ( T const& x, optional<T> const& y ) bool operator != ( T const& x, optional<T> const& y )
{ return !( x == y ) ; } { return !( x == y ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator > ( T const& x, optional<T> const& y ) bool operator > ( T const& x, optional<T> const& y )
{ return y < x ; } { return y < x ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator <= ( T const& x, optional<T> const& y ) bool operator <= ( T const& x, optional<T> const& y )
{ return !( y < x ) ; } { return !( y < x ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator >= ( T const& x, optional<T> const& y ) bool operator >= ( T const& x, optional<T> const& y )
{ return !( x < y ) ; } { return !( x < y ) ; }
@@ -128,33 +128,33 @@ bool operator >= ( T const& x, optional<T> const& y )
// //
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator == ( optional<T> const& x, none_t ) BOOST_NOEXCEPT bool operator == ( optional<T> const& x, none_t ) BOOST_NOEXCEPT
{ return !x; } { return !x; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator < ( optional<T> const&, none_t ) bool operator < ( optional<T> const&, none_t ) BOOST_NOEXCEPT
{ return false; } { return false; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator != ( optional<T> const& x, none_t ) BOOST_NOEXCEPT bool operator != ( optional<T> const& x, none_t ) BOOST_NOEXCEPT
{ return bool(x); } { return bool(x); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator > ( optional<T> const& x, none_t y ) bool operator > ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
{ return y < x ; } { return y < x ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator <= ( optional<T> const& x, none_t y ) bool operator <= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
{ return !( y < x ) ; } { return !( y < x ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator >= ( optional<T> const& x, none_t y ) bool operator >= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
{ return !( x < y ) ; } { return !( x < y ) ; }
// //
@@ -162,33 +162,33 @@ bool operator >= ( optional<T> const& x, none_t y )
// //
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator == ( none_t , optional<T> const& y ) BOOST_NOEXCEPT bool operator == ( none_t , optional<T> const& y ) BOOST_NOEXCEPT
{ return !y; } { return !y; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator < ( none_t , optional<T> const& y ) bool operator < ( none_t , optional<T> const& y ) BOOST_NOEXCEPT
{ return bool(y); } { return bool(y); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator != ( none_t, optional<T> const& y ) BOOST_NOEXCEPT bool operator != ( none_t, optional<T> const& y ) BOOST_NOEXCEPT
{ return bool(y); } { return bool(y); }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator > ( none_t x, optional<T> const& y ) bool operator > ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
{ return y < x ; } { return y < x ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator <= ( none_t x, optional<T> const& y ) bool operator <= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
{ return !( y < x ) ; } { return !( y < x ) ; }
template<class T> template<class T>
inline inline BOOST_CONSTEXPR
bool operator >= ( none_t x, optional<T> const& y ) bool operator >= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
{ return !( x < y ) ; } { return !( x < y ) ; }
} // namespace boost } // namespace boost
@@ -0,0 +1,37 @@
// Copyright (C) 2026 Andrzej Krzemieński.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
//
//
// This header provides definitions required by any specialization of
// optional<>.
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_SELECT_IMPLEMENTATION_01FEB2026_HPP
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_SELECT_IMPLEMENTATION_01FEB2026_HPP
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_CONSTEXPR) && \
!defined(BOOST_NO_CXX11_REF_QUALIFIERS) && \
!defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
!defined(BOOST_NO_CXX11_UNRESTRICTED_UNION) && \
!defined(BOOST_NO_CXX11_NOEXCEPT) && \
!defined(BOOST_NO_CXX11_DEFAULTED_MOVES) && \
!defined(BOOST_OPTIONAL_CONFIG_DISABLE_UNION_OPTIONAL)
# define BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#endif
// In C++20 we have `std::construct_at()` which is a constexpr equivalent of
// placement-new. We can then make more functions constexpr.
// TBD: This additional constexpr-ication is left for the future.
# define BOOST_OPTIONAL_CXX20_CONSTEXPR
#endif //BOOST_OPTIONAL_DETAIL_OPTIONAL_SELECT_IMPLEMENTATION_01FEB2026_HPP
@@ -54,7 +54,7 @@ struct swap_selector<true>
#endif #endif
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
# define BOOST_OPTIONAL_DETAIL_MOVE(EXPR_) optional_detail::move(EXPR_) # define BOOST_OPTIONAL_DETAIL_MOVE(EXPR_) optional_detail::move_(EXPR_)
#else #else
# define BOOST_OPTIONAL_DETAIL_MOVE(EXPR_) EXPR_ # define BOOST_OPTIONAL_DETAIL_MOVE(EXPR_) EXPR_
#endif #endif
@@ -54,7 +54,7 @@ class tc_optional_base : public optional_tag
: :
m_initialized(false) m_initialized(false)
{ {
construct(optional_detail::forward<Expr>(expr),tag); construct(optional_detail::forward_<Expr>(expr),tag);
} }
// tc_optional_base& operator= ( tc_optional_base const& ) = default; // tc_optional_base& operator= ( tc_optional_base const& ) = default;
@@ -102,7 +102,7 @@ class tc_optional_base : public optional_tag
template<class Expr, class ExprPtr> template<class Expr, class ExprPtr>
void assign_expr ( Expr&& expr, ExprPtr const* tag ) void assign_expr ( Expr&& expr, ExprPtr const* tag )
{ {
construct(optional_detail::forward<Expr>(expr),tag); construct(optional_detail::forward_<Expr>(expr),tag);
} }
#endif #endif
@@ -138,14 +138,14 @@ class tc_optional_base : public optional_tag
template<class... Args> template<class... Args>
void construct ( in_place_init_t, Args&&... args ) void construct ( in_place_init_t, Args&&... args )
{ {
m_storage = value_type( optional_detail::forward<Args>(args)... ) ; m_storage = value_type( optional_detail::forward_<Args>(args)... ) ;
m_initialized = true ; m_initialized = true ;
} }
template<class... Args> template<class... Args>
void emplace_assign ( Args&&... args ) void emplace_assign ( Args&&... args )
{ {
construct(in_place_init, optional_detail::forward<Args>(args)...); construct(in_place_init, optional_detail::forward_<Args>(args)...);
} }
template<class... Args> template<class... Args>
@@ -153,7 +153,7 @@ class tc_optional_base : public optional_tag
: :
m_initialized(false) m_initialized(false)
{ {
construct(in_place_init, optional_detail::forward<Args>(args)...); construct(in_place_init, optional_detail::forward_<Args>(args)...);
} }
template<class... Args> template<class... Args>
@@ -162,7 +162,7 @@ class tc_optional_base : public optional_tag
m_initialized(false) m_initialized(false)
{ {
if ( cond ) if ( cond )
construct(in_place_init, optional_detail::forward<Args>(args)...); construct(in_place_init, optional_detail::forward_<Args>(args)...);
} }
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
@@ -207,7 +207,7 @@ class tc_optional_base : public optional_tag
template<class Expr> template<class Expr>
void construct ( Expr&& expr, void const* ) void construct ( Expr&& expr, void const* )
{ {
m_storage = value_type(optional_detail::forward<Expr>(expr)) ; m_storage = value_type(optional_detail::forward_<Expr>(expr)) ;
m_initialized = true ; m_initialized = true ;
} }
@@ -218,7 +218,7 @@ class tc_optional_base : public optional_tag
template<class Expr> template<class Expr>
void assign_expr_to_initialized ( Expr&& expr, void const* ) void assign_expr_to_initialized ( Expr&& expr, void const* )
{ {
assign_value( optional_detail::forward<Expr>(expr) ); assign_value( optional_detail::forward_<Expr>(expr) );
} }
#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION #ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
@@ -1,41 +0,0 @@
// Copyright (C) 2024 Ryan Malcolm Underwood.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/optional for documentation.
//
// You are welcome to contact the author at:
// typenametea@gmail.com
#ifndef BOOST_OPTIONAL_OPTIONAL_DETAIL_OPTIONAL_UTILITY_RMU_06OCT2024_HPP
#define BOOST_OPTIONAL_OPTIONAL_DETAIL_OPTIONAL_UTILITY_RMU_06OCT2024_HPP
namespace boost {
namespace optional_detail {
// Workaround: forward and move aren't constexpr in C++11
template <class T>
inline constexpr T&& forward(typename boost::remove_reference<T>::type& t) noexcept
{
return static_cast<T&&>(t);
}
template <class T>
inline constexpr T&& forward(typename boost::remove_reference<T>::type&& t) noexcept
{
static_assert(!boost::is_lvalue_reference<T>::value, "Can not forward an rvalue as an lvalue.");
return static_cast<T&&>(t);
}
template <class T>
inline constexpr typename boost::remove_reference<T>::type&& move(T&& t) noexcept
{
return static_cast<typename boost::remove_reference<T>::type&&>(t);
}
} // namespace optional_detail
} // namespace boost
#endif
@@ -0,0 +1,724 @@
// Copyright (C) 2026 Andrzej Krzemieński.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
//
//
// This header provides definitions required by any specialization of
// optional<>.
#ifndef BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
#define BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
//#include <initializer_list>
#include <boost/assert.hpp>
#include <boost/core/invoke_swap.hpp>
#include <boost/throw_exception.hpp>
#include <boost/optional/bad_optional_access.hpp>
// This macro shall be put in the position of a template parameter.
// It emulates the requires clause.
# define BOOST_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false
# ifdef __cpp_guaranteed_copy_elision
# if __cpp_guaranteed_copy_elision
# define BOOST_OPTIONAL_CONSTEXPR_COPY
# endif
# endif
template <typename T, typename U>
struct fail_hard_on_nonconvertible
{
static_assert(::std::is_convertible<U&&, T>::value, "The argument must be convertible to T");
using type = bool;
};
// Missing C++17 type traits
namespace boost { namespace optional_detail {
template <class...>
struct conjunction : ::std::true_type {};
template <class B1>
struct conjunction<B1> : B1 {};
template <class B1, class... Bn>
struct conjunction<B1, Bn...>
: ::std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
}}
namespace boost { namespace optional_detail {
// Tag to indicate a special-purpose constructor
BOOST_INLINE_VARIABLE constexpr struct trivial_init_t{} trivial_init{};
template <class T>
union constexpr_union_storage_t
{
static_assert(::std::is_trivially_destructible<T>::value, "!!");
unsigned char dummy_;
T value_;
constexpr constexpr_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
// false positive, see https://github.com/boostorg/variant2/issues/55,
// https://github.com/boostorg/url/issues/979
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <class... Args>
constexpr constexpr_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
# pragma GCC diagnostic pop
#endif
//~constexpr_union_storage_t() = default; // No need to destroy a trivially-destructible type
};
template <class T>
union fallback_union_storage_t
{
unsigned char dummy_;
T value_;
constexpr fallback_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
// false positive, see https://github.com/boostorg/variant2/issues/55,
// https://github.com/boostorg/url/issues/979
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <class... Args>
constexpr fallback_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
# pragma GCC diagnostic pop
#endif
~fallback_union_storage_t(){} // My owner will destroy the `T` if needed.
// Cannot default in a union with nontrivial `T`.
};
// `guarded_storage` is a union + a flag indicating if a `T` has been initialized.
// this way the destructor knows if it should destroy the `T`.
template <class T>
struct constexpr_guarded_storage
{
static_assert(::std::is_trivially_destructible<T>::value, "!!");
bool init_;
constexpr_union_storage_t<T> storage_;
constexpr constexpr_guarded_storage() noexcept : init_(false), storage_(trivial_init) {};
explicit constexpr constexpr_guarded_storage(const T& v) : init_(true), storage_(v) {}
explicit constexpr constexpr_guarded_storage(T&& v) : init_(true), storage_(move_(v)) {}
template <class... Args> explicit constexpr constexpr_guarded_storage(optional_ns::in_place_init_t, Args&&... args)
: init_(true), storage_(forward_<Args>(args)...) {}
// template <class U, class... Args, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)>
// constexpr explicit constexpr_guarded_storage(optional_ns::in_place_init_t, ::std::initializer_list<U> il, Args&&... args)
// : init_(true), storage_(il, forward_<Args>(args)...) {}
BOOST_CXX14_CONSTEXPR void reset () noexcept { init_ = false; }
//~constexpr_guarded_storage() = default;
#if (defined(_MSC_VER) && 1910 <= _MSC_VER && _MSC_VER <= 1916)
// Workaround for MSVC 14.1x bug where it eagerly tries to define the copy/move operations
// these are declared but never defined
constexpr_guarded_storage(const constexpr_guarded_storage&);
constexpr_guarded_storage(constexpr_guarded_storage&&);
constexpr_guarded_storage& operator=(const constexpr_guarded_storage&);
constexpr_guarded_storage& operator=(constexpr_guarded_storage&&);
#endif
};
template <class T>
struct fallback_guarded_storage
{
bool init_;
fallback_union_storage_t<T> storage_;
constexpr fallback_guarded_storage() noexcept : init_(false), storage_(trivial_init) {};
explicit constexpr fallback_guarded_storage(const T& v) : init_(true), storage_(v) {}
explicit constexpr fallback_guarded_storage(T&& v) : init_(true), storage_(move_(v)) {}
template <class... Args> explicit constexpr fallback_guarded_storage(optional_ns::in_place_init_t, Args&&... args)
: init_(true), storage_(forward_<Args>(args)...) {}
// template <class U, class... Args, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)>
// explicit fallback_guarded_storage(optional_ns::in_place_init_t, ::std::initializer_list<U> il, Args&&... args)
// : init_(true), storage_(il, forward_<Args>(args)...) {}
void reset() noexcept
{
if (init_)
{
storage_.value_.T::~T();
init_ = false;
}
}
~fallback_guarded_storage() { if (init_) storage_.value_.T::~T(); }
#if (defined(_MSC_VER) && 1910 <= _MSC_VER && _MSC_VER <= 1916)
// Workaround for MSVC 14.1x bug where it eagerly tries to define the copy/move operations
// These are declared but never defined
fallback_guarded_storage(const fallback_guarded_storage&);
fallback_guarded_storage(fallback_guarded_storage&&);
fallback_guarded_storage& operator=(const fallback_guarded_storage&);
fallback_guarded_storage& operator=(fallback_guarded_storage&&);
#endif
};
template <class T>
using guarded_storage = typename ::std::conditional<
::std::is_trivially_destructible<T>::value, // if possible
constexpr_guarded_storage<typename ::std::remove_const<T>::type>, // use storage with trivial destructor
fallback_guarded_storage<typename ::std::remove_const<T>::type>
>::type;
}}
namespace boost {
template <class T>
class optional : public optional_detail::optional_tag
{
using storage_t = optional_detail::guarded_storage<T>;
storage_t storage;
static_assert( !::std::is_same<typename std::decay<T>::type, none_t>::value, "optional<none_t> is illegal" );
static_assert( !::std::is_same<typename std::decay<T>::type, in_place_init_t>::value, "optional<in_place_init_t> is illegal" );
static_assert( !::std::is_same<typename std::decay<T>::type, in_place_init_if_t>::value, "optional<in_place_init_if_t> is illegal" );
BOOST_CXX14_CONSTEXPR typename ::std::remove_const<T>::type* dataptr() { return ::boost::addressof(storage.storage_.value_); }
constexpr const T* dataptr() const { return ::boost::addressof(storage.storage_.value_); }
constexpr const T& contained_val() const& { return storage.storage_.value_; }
BOOST_CXX14_CONSTEXPR T&& contained_val() && { return optional_detail::move_(storage.storage_.value_); }
BOOST_CXX14_CONSTEXPR T& contained_val() & { return storage.storage_.value_; }
template <typename... Args>
BOOST_OPTIONAL_CXX20_CONSTEXPR void initialize(Args&&... args)
{
BOOST_ASSERT(!storage.init_);
::new (static_cast<void*>(dataptr())) T(optional_detail::forward_<Args>(args)...);
storage.init_ = true;
}
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
// The conditional initialization of storage needs to employ a factory
// function, so that we can utilize the guaranteed copy elision on the
// return type.
// an alternative -- using a conditional operator in the initializer --
// does not work in MSVC 14.2 and 14.3.
template <typename... U>
static constexpr storage_t conditional_storage_from_values(bool cond, U&&... v)
{
if (cond)
return storage_t(in_place_init, optional_detail::forward_<U>(v)...);
else
return storage_t();
}
template <typename OU>
static constexpr storage_t conditional_storage_from_optional(OU&& ou)
{
if (ou.has_value())
return storage_t(in_place_init, *optional_detail::forward_<OU>(ou));
else
return storage_t();
}
#endif
public:
using value_type = T;
using unqualified_value_type = typename ::std::remove_const<T>::type;
using reference_type = T&;
using reference_const_type = T const&;
using argument_type = T const&;
using rval_reference_type = T&&;
using reference_type_of_temporary_wrapper = T&&;
using pointer_type = T*;
using pointer_const_type = T const*;
constexpr bool is_initialized() const noexcept { return storage.init_; }
constexpr optional() noexcept : storage() {};
constexpr optional(none_t) noexcept : storage() {};
constexpr optional(const T& v) : storage(v) {}
constexpr optional(T&& v) : storage(optional_detail::move_(v)) {}
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
constexpr optional(bool cond, const T& v)
: storage(conditional_storage_from_values(cond, v))
{}
constexpr optional(bool cond, T&& v)
: storage(conditional_storage_from_values(cond, optional_detail::move_(v)))
{}
constexpr optional(const optional& rhs)
: storage(conditional_storage_from_optional(rhs))
{}
constexpr optional(optional&& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value)
: storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
{}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)>
constexpr explicit optional(optional<U> const& rhs)
: storage(conditional_storage_from_optional(rhs))
{}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
constexpr explicit optional(optional<U> && rhs)
: storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
{}
template <typename... Args>
constexpr explicit optional( in_place_init_if_t, bool cond, Args&&... args )
: storage(conditional_storage_from_values(cond, optional_detail::forward_<Args>(args)...))
{}
#else
optional(bool cond, const T& v)
: storage()
{
if (cond)
initialize(v);
}
optional(bool cond, T&& v)
: storage()
{
if (cond)
initialize(optional_detail::move_(v));
}
optional(const optional& rhs)
: storage()
{
if (rhs.is_initialized())
initialize(*rhs);
}
optional(optional&& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value)
: storage()
{
if (rhs.is_initialized())
initialize(*optional_detail::move_(rhs));
}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)>
explicit optional(optional<U> const& rhs)
: storage()
{
if (rhs.is_initialized())
initialize(*rhs);
}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
explicit optional(optional<U> && rhs)
: storage()
{
if (rhs.is_initialized())
initialize(*optional_detail::move_(rhs));
}
template <typename... Args>
explicit optional( in_place_init_if_t, bool cond, Args&&... args )
: storage()
{
if (cond)
initialize(optional_detail::forward_<Args>(args)...);
}
#endif // BOOST_OPTIONAL_CONSTEXPR_COPY
template <typename FT,
BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<FT>)>
/*non-constexpr (deprecated)*/
explicit optional (FT&& factory)
: storage()
{
factory.apply(this->dataptr());
storage.init_ = true ;
}
template <typename FT,
BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<FT>)>
/*non-constexpr (deprecated)*/
explicit optional (FT&& factory)
: storage()
{
boost_optional_detail::construct<value_type>(factory, this->dataptr());
storage.init_ = true;
}
template <typename U,
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_typed_in_place_factory<U>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_in_place_factory<U>),
BOOST_OPTIONAL_REQUIRES(!BOOST_OPTIONAL_IS_TAGGED(optional_detail::optional_tag, U))
>
constexpr explicit optional(U&& v)
: storage(optional_ns::in_place_init, optional_detail::forward_<U>(v))
{}
template <typename... Args>
constexpr explicit optional( in_place_init_t, Args&&... args )
: storage(in_place_init, optional_detail::forward_<Args>(args)...)
{}
BOOST_CXX14_CONSTEXPR operator optional<T&>() & noexcept
{
return this->has_value() ? optional<T&>(**this) : optional<T&>();
}
BOOST_CONSTEXPR operator optional<const T&>() const& noexcept
{
return this->has_value() ? optional<const T&>(**this) : optional<const T&>();
}
BOOST_CXX14_CONSTEXPR operator optional<T&>() && noexcept = delete;
BOOST_CONSTEXPR operator optional<const T&>() const&& noexcept = delete;
BOOST_CXX14_CONSTEXPR void reset() noexcept
{
storage.reset();
}
BOOST_OPTIONAL_CXX20_CONSTEXPR void reset(const T& v)
{
*this = v;
}
template <typename... Args>
BOOST_OPTIONAL_CXX20_CONSTEXPR void emplace(Args&&... args)
{
reset();
// <-- now we are not containing a value
initialize(optional_detail::forward_<Args>(args)...);
}
BOOST_CXX14_CONSTEXPR optional& operator=(none_t) noexcept
{
reset();
return *this;
}
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(const optional& rhs)
{
if (has_value())
{
if (rhs.has_value())
**this = *rhs;
else
reset();
}
else
{
if (rhs.has_value())
initialize(*rhs);
}
return *this;
}
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(optional&& rhs)
noexcept(::std::is_nothrow_move_assignable<T>::value && ::std::is_nothrow_move_constructible<T>::value)
{
if (has_value())
{
if (rhs.has_value())
**this = *optional_detail::move_(rhs);
else
reset();
}
else
{
if (rhs.has_value())
initialize(*optional_detail::move_(rhs) );
}
return *this;
}
template <typename U>
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(const optional<U>& rhs)
{
if (has_value())
{
if (rhs.has_value())
**this = *rhs;
else
reset();
}
else
{
if (rhs.has_value())
initialize(*rhs);
}
return *this;
}
template <typename U>
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(optional<U>&& rhs)
{
if (has_value())
{
if (rhs.has_value())
**this = *optional_detail::move_(rhs);
else
reset();
}
else
{
if (rhs.has_value())
initialize(*optional_detail::move_(rhs));
}
return *this;
}
template <class U = typename ::std::remove_cv<T>::type,
BOOST_OPTIONAL_REQUIRES(!::std::is_same<typename ::std::decay<U>::type, optional>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::conjunction<::std::is_scalar<T>, ::std::is_same<T, BOOST_OPTIONAL_DECAY(U)>>),
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U>),
BOOST_OPTIONAL_REQUIRES(::std::is_assignable<T&, U>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_typed_in_place_factory<U>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_in_place_factory<U>)
>
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(U&& v)
{
if (is_initialized())
contained_val() = optional_detail::forward_<U>(v);
else
initialize(optional_detail::forward_<U>(v));
return *this;
}
template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<F>)>
/*non-constexpr (deprecated)*/
optional& operator=(F&& factory)
{
reset();
boost_optional_detail::construct<value_type>(factory, this->dataptr());
storage.init_ = true;
return *this;
}
template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<F>)>
/*non-constexpr (deprecated)*/
optional& operator=(F&& factory)
{
reset();
factory.apply(this->dataptr());
storage.init_ = true;
return *this;
}
BOOST_OPTIONAL_CXX20_CONSTEXPR
void swap(optional& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*rhs, *rhs)))
{
if (is_initialized())
{
if (rhs.is_initialized())
boost::core::invoke_swap(contained_val(), rhs.contained_val());
else
{ rhs.initialize(optional_detail::move_(*this).contained_val()); reset(); }
}
else
{
if (rhs.is_initialized())
{ initialize(optional_detail::move_(rhs).contained_val()); rhs.reset(); }
}
}
~optional() = default; // The destructor in `storage`, based on the specialization
// will be trivial or not.
constexpr bool has_value() const noexcept { return this->is_initialized(); }
constexpr explicit operator bool() const noexcept { return this->is_initialized(); }
constexpr reference_const_type get() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(this->is_initialized(), this->contained_val()); }
BOOST_CXX14_CONSTEXPR reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return this->contained_val(); }
//BOOST_DEPRECATED("use `value_or(v)` instead")
reference_const_type get_value_or (reference_const_type v) const { return this->is_initialized() ? this->contained_val() : v; }
//BOOST_DEPRECATED("use `value_or(v)` instead")
reference_type get_value_or (reference_type v) { return this->is_initialized() ? this->contained_val() : v; }
pointer_const_type get_ptr() const { return is_initialized() ? dataptr() : nullptr; }
pointer_type get_ptr() { return is_initialized() ? dataptr() : nullptr; }
constexpr reference_const_type operator*() const& { return this->get(); }
BOOST_CXX14_CONSTEXPR reference_type operator*() & { return this->get(); }
BOOST_CXX14_CONSTEXPR reference_type_of_temporary_wrapper operator*() && { return optional_detail::move_(this->get()); }
constexpr pointer_const_type operator->() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(this->is_initialized(), this->dataptr()); }
BOOST_CXX14_CONSTEXPR pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->dataptr(); }
constexpr reference_const_type value() const&
{
return this->is_initialized() ? this->get() : (boost::throw_exception(boost::bad_optional_access()), this->get());
}
BOOST_CXX14_CONSTEXPR reference_type value() &
{
if (this->is_initialized())
return this->get();
else
boost::throw_exception(boost::bad_optional_access());
}
BOOST_CXX14_CONSTEXPR reference_type_of_temporary_wrapper value() &&
{
if (this->is_initialized())
return optional_detail::move_(this->get());
else
boost::throw_exception(boost::bad_optional_access());
}
template <class U = typename ::std::remove_cv<T>::type,
typename fail_hard_on_nonconvertible<T, U>::type = true>
constexpr value_type value_or(U&& v) const&
{
return this->is_initialized() ? get() : T(optional_detail::forward_<U>(v));
}
template <class U = typename ::std::remove_cv<T>::type>
BOOST_CXX14_CONSTEXPR value_type value_or(U&& v) &&
{
if (this->is_initialized())
return optional_detail::move_(get());
else
return optional_detail::forward_<U>(v);
}
template <typename F,
typename fail_hard_on_nonconvertible<T, decltype(optional_detail::declval_<F>()())>::type = true>
constexpr value_type value_or_eval(F f) const&
{
return this->is_initialized() ? get() : value_type(f());
}
template <typename F>
BOOST_CXX14_CONSTEXPR value_type value_or_eval ( F f ) &&
{
if (this->is_initialized())
return optional_detail::move_(get());
else
return f();
}
template <typename F>
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_of<F, reference_type>::type>
map(F f) &
{
if (this->has_value())
return f(get());
else
return none;
}
template <typename F>
constexpr optional<typename optional_detail::result_of<F, reference_const_type>::type>
map(F f) const&
{
return this->has_value() ?
f(get()) :
optional<typename optional_detail::result_of<F, reference_const_type>::type>();
}
template <typename F>
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_of<F, reference_type_of_temporary_wrapper>::type>
map(F f) &&
{
if (this->has_value())
return f(optional_detail::move_(this->get()));
else
return none;
}
template <typename F>
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_value_type<F, reference_type>::type>
flat_map(F f) &
{
if (this->has_value())
return f(get());
else
return none;
}
template <typename F>
constexpr optional<typename optional_detail::result_value_type<F, reference_const_type>::type>
flat_map(F f) const&
{
return this->has_value() ?
f(get()) :
optional<typename optional_detail::result_value_type<F, reference_const_type>::type>();
}
template <typename F>
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_value_type<F, reference_type_of_temporary_wrapper>::type>
flat_map(F f) &&
{
if (this->has_value())
return f(optional_detail::move_(get()));
else
return none;
}
};
template <typename T>
BOOST_OPTIONAL_CXX20_CONSTEXPR
void swap(optional<T>& lhs, optional<T>& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*lhs, *rhs)))
{
lhs.swap(rhs);
}
}
#endif // BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
+101 -228
View File
@@ -1,5 +1,5 @@
// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
// Copyright (C) 2014 - 2021 Andrzej Krzemienski. // Copyright (C) 2014 - 2026 Andrzej Krzemieński.
// //
// Use, modification, and distribution is subject to the Boost Software // Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -7,23 +7,56 @@
// //
// See http://www.boost.org/libs/optional for documentation. // See http://www.boost.org/libs/optional for documentation.
// //
// You are welcome to contact the author at: // You are welcome to contact the authors at:
// fernando_cacciola@hotmail.com // fernando_cacciola@hotmail.com
// akrzemi1@gmail.com
//
// You can file a GitHub issue at:
// https://github.com/boostorg/optional/issues
// //
// Revisions: // Revisions:
// 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen // 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen
// 05 May 2014 (Added move semantics) Andrzej Krzemienski // 05 May 2014 (Added move semantics) Andrzej Krzemienski
// 01 Feb 2026 Added constexpr implementaiton for C++14
// //
#ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#include <new>
#include <boost/optional/detail/optional_select_implementation.hpp>
#include <boost/optional/detail/optional_common_defs.hpp>
#ifndef BOOST_NO_IOSTREAM #ifndef BOOST_NO_IOSTREAM
#include <iosfwd> #include <iosfwd>
namespace boost {
// The following declaration prevents a bug where operator safe-bool is used upon streaming optional object if you forget the IO header.
template<class CharType, class CharTrait>
std::basic_ostream<CharType, CharTrait>&
operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optional_tag const&)
{
static_assert(sizeof(CharType) == 0, "If you want to output boost::optional, include header <boost/optional/optional_io.hpp>");
return os;
}
} // namespace boost
#endif // BOOST_NO_IOSTREAM #endif // BOOST_NO_IOSTREAM
#include <boost/none.hpp>
#if defined BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#include <boost/optional/detail/union_optional.hpp>
#else
#include <new>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/core/addressof.hpp>
#include <boost/core/enable_if.hpp> #include <boost/core/enable_if.hpp>
#include <boost/core/invoke_swap.hpp> #include <boost/core/invoke_swap.hpp>
#include <boost/core/launder.hpp> #include <boost/core/launder.hpp>
@@ -50,83 +83,18 @@
#include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_volatile.hpp> #include <boost/type_traits/is_volatile.hpp>
#include <boost/type_traits/is_scalar.hpp> #include <boost/type_traits/is_scalar.hpp>
#include <boost/none.hpp>
#include <boost/optional/optional_fwd.hpp> #include <boost/optional/optional_fwd.hpp>
#include <boost/optional/detail/optional_config.hpp> #include <boost/optional/detail/optional_config.hpp>
#include <boost/optional/detail/optional_factory_support.hpp>
#include <boost/optional/detail/optional_aligned_storage.hpp> #include <boost/optional/detail/optional_aligned_storage.hpp>
#include <boost/optional/detail/optional_hash.hpp>
#include <boost/optional/detail/optional_utility.hpp>
namespace boost { namespace optional_detail {
template <typename T>
struct optional_value_type
{
};
template <typename U>
struct optional_value_type< ::boost::optional<U> >
{
typedef U type;
};
template <typename T>
T declval();
// implementing my own result_of so that it works for C++11 (std::result_of)
// and in C++20 (std::invoke_result).
template <typename F, typename Ref, typename Rslt = decltype(declval<F>()(declval<Ref>()))>
struct result_of
{
typedef Rslt type;
};
template <typename F, typename Ref, typename Rslt = typename optional_value_type<typename result_of<F, Ref>::type>::type>
struct result_value_type
{
typedef Rslt type;
};
// optional<typename optional_detail::optional_value_type<decltype(optional_detail::declval<F>()(optional_detail::declval<reference_type>()))>::type>
}} // namespace boost::optional_detail
namespace boost { namespace boost {
namespace optional_ns {
// a tag for in-place initialization of contained value
struct in_place_init_t
{
struct init_tag{};
BOOST_CONSTEXPR explicit in_place_init_t(init_tag){}
};
BOOST_INLINE_CONSTEXPR in_place_init_t in_place_init ((in_place_init_t::init_tag()));
// a tag for conditional in-place initialization of contained value
struct in_place_init_if_t
{
struct init_tag{};
BOOST_CONSTEXPR explicit in_place_init_if_t(init_tag){}
};
BOOST_INLINE_CONSTEXPR in_place_init_if_t in_place_init_if ((in_place_init_if_t::init_tag()));
} // namespace optional_ns
using optional_ns::in_place_init_t;
using optional_ns::in_place_init;
using optional_ns::in_place_init_if_t;
using optional_ns::in_place_init_if;
namespace optional_detail { namespace optional_detail {
struct init_value_tag {}; struct init_value_tag {};
struct optional_tag {};
template<class T> template<class T>
class optional_base : public optional_tag class optional_base : public optional_tag
@@ -177,7 +145,7 @@ class optional_base : public optional_tag
: :
m_initialized(false) m_initialized(false)
{ {
construct( optional_detail::move(val) ); construct( optional_detail::move_(val) );
} }
// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional<T>. // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional<T>.
@@ -197,7 +165,7 @@ class optional_base : public optional_tag
m_initialized(false) m_initialized(false)
{ {
if ( cond ) if ( cond )
construct(optional_detail::move(val)); construct(optional_detail::move_(val));
} }
// Creates a deep copy of another optional<T> // Creates a deep copy of another optional<T>
@@ -218,7 +186,7 @@ class optional_base : public optional_tag
m_initialized(false) m_initialized(false)
{ {
if ( rhs.is_initialized() ) if ( rhs.is_initialized() )
construct( optional_detail::move(rhs.get_impl()) ); construct( optional_detail::move_(rhs.get_impl()) );
} }
@@ -227,7 +195,7 @@ class optional_base : public optional_tag
: :
m_initialized(false) m_initialized(false)
{ {
construct(optional_detail::forward<Expr>(expr),tag); construct(optional_detail::forward_<Expr>(expr),tag);
} }
optional_base& operator= ( optional_base const& rhs ) optional_base& operator= ( optional_base const& rhs )
@@ -268,13 +236,13 @@ class optional_base : public optional_tag
if (is_initialized()) if (is_initialized())
{ {
if ( rhs.is_initialized() ) if ( rhs.is_initialized() )
assign_value( optional_detail::move(rhs.get_impl()) ); assign_value( optional_detail::move_(rhs.get_impl()) );
else destroy(); else destroy();
} }
else else
{ {
if ( rhs.is_initialized() ) if ( rhs.is_initialized() )
construct(optional_detail::move(rhs.get_impl())); construct(optional_detail::move_(rhs.get_impl()));
} }
} }
@@ -334,8 +302,8 @@ class optional_base : public optional_tag
void assign ( rval_reference_type val ) void assign ( rval_reference_type val )
{ {
if (is_initialized()) if (is_initialized())
assign_value( optional_detail::move(val) ); assign_value( optional_detail::move_(val) );
else construct( optional_detail::move(val) ); else construct( optional_detail::move_(val) );
} }
// Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED
@@ -348,8 +316,8 @@ class optional_base : public optional_tag
void assign_expr ( Expr&& expr, ExprPtr const* tag ) void assign_expr ( Expr&& expr, ExprPtr const* tag )
{ {
if (is_initialized()) if (is_initialized())
assign_expr_to_initialized(optional_detail::forward<Expr>(expr),tag); assign_expr_to_initialized(optional_detail::forward_<Expr>(expr),tag);
else construct(optional_detail::forward<Expr>(expr),tag); else construct(optional_detail::forward_<Expr>(expr),tag);
} }
#endif #endif
@@ -381,7 +349,7 @@ class optional_base : public optional_tag
void construct ( rval_reference_type val ) void construct ( rval_reference_type val )
{ {
::new (m_storage.address()) unqualified_value_type( optional_detail::move(val) ) ; ::new (m_storage.address()) unqualified_value_type( optional_detail::move_(val) ) ;
m_initialized = true ; m_initialized = true ;
} }
@@ -391,7 +359,7 @@ class optional_base : public optional_tag
template<class... Args> template<class... Args>
void construct ( in_place_init_t, Args&&... args ) void construct ( in_place_init_t, Args&&... args )
{ {
::new (m_storage.address()) unqualified_value_type( optional_detail::forward<Args>(args)... ) ; ::new (m_storage.address()) unqualified_value_type( optional_detail::forward_<Args>(args)... ) ;
m_initialized = true ; m_initialized = true ;
} }
@@ -399,7 +367,7 @@ class optional_base : public optional_tag
void emplace_assign ( Args&&... args ) void emplace_assign ( Args&&... args )
{ {
destroy(); destroy();
construct(in_place_init, optional_detail::forward<Args>(args)...); construct(in_place_init, optional_detail::forward_<Args>(args)...);
} }
template<class... Args> template<class... Args>
@@ -407,7 +375,7 @@ class optional_base : public optional_tag
: :
m_initialized(false) m_initialized(false)
{ {
construct(in_place_init, optional_detail::forward<Args>(args)...); construct(in_place_init, optional_detail::forward_<Args>(args)...);
} }
template<class... Args> template<class... Args>
@@ -416,7 +384,7 @@ class optional_base : public optional_tag
m_initialized(false) m_initialized(false)
{ {
if ( cond ) if ( cond )
construct(in_place_init, optional_detail::forward<Args>(args)...); construct(in_place_init, optional_detail::forward_<Args>(args)...);
} }
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
@@ -461,7 +429,7 @@ class optional_base : public optional_tag
template<class Expr> template<class Expr>
void construct ( Expr&& expr, void const* ) void construct ( Expr&& expr, void const* )
{ {
new (m_storage.address()) unqualified_value_type(optional_detail::forward<Expr>(expr)) ; new (m_storage.address()) unqualified_value_type(optional_detail::forward_<Expr>(expr)) ;
m_initialized = true ; m_initialized = true ;
} }
@@ -472,7 +440,7 @@ class optional_base : public optional_tag
template<class Expr> template<class Expr>
void assign_expr_to_initialized ( Expr&& expr, void const* ) void assign_expr_to_initialized ( Expr&& expr, void const* )
{ {
assign_value( optional_detail::forward<Expr>(expr) ); assign_value( optional_detail::forward_<Expr>(expr) );
} }
#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION #ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
@@ -497,7 +465,7 @@ class optional_base : public optional_tag
{ {
// An exception can be thrown here. // An exception can be thrown here.
// It it happens, THIS will be left uninitialized. // It it happens, THIS will be left uninitialized.
new (m_storage.address()) unqualified_value_type(optional_detail::move(expr.get())) ; new (m_storage.address()) unqualified_value_type(optional_detail::move_(expr.get())) ;
m_initialized = true ; m_initialized = true ;
} }
} }
@@ -548,16 +516,15 @@ struct has_dedicated_constructor
{}; {};
template <typename U> template <typename U>
struct is_in_place_factory struct is_factory
: boost::disjunction< boost::is_base_of<boost::in_place_factory_base, BOOST_DEDUCED_TYPENAME boost::decay<U>::type>, : boost::disjunction< is_in_place_factory<U>, is_typed_in_place_factory<U> >
boost::is_base_of<boost::typed_in_place_factory_base, BOOST_DEDUCED_TYPENAME boost::decay<U>::type> >
{}; {};
#if !defined(BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT) #if !defined(BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT)
template <typename T, typename U> template <typename T, typename U>
struct is_factory_or_constructible_to_T struct is_factory_or_constructible_to_T
: boost::disjunction< is_in_place_factory<U>, boost::is_constructible<T, U&&> > : boost::disjunction< is_factory<U>, boost::is_constructible<T, U&&> >
{}; {};
template <typename T, typename U> template <typename T, typename U>
@@ -597,7 +564,7 @@ struct is_opt_assignable : boost::is_convertible<U, T>
template <typename T, typename U> template <typename T, typename U>
struct is_factory_or_opt_assignable_to_T struct is_factory_or_opt_assignable_to_T
: boost::disjunction< is_in_place_factory<U>, is_opt_assignable<T, U> > : boost::disjunction< is_factory<U>, is_opt_assignable<T, U> >
{}; {};
template <typename T, typename U, bool = has_dedicated_constructor<T, U>::value> template <typename T, typename U, bool = has_dedicated_constructor<T, U>::value>
@@ -675,7 +642,7 @@ class optional
// Creates an optional<T> initialized with 'move(val)'. // Creates an optional<T> initialized with 'move(val)'.
// Can throw if T::T(T &&) does // Can throw if T::T(T &&) does
optional ( rval_reference_type val ) : base(optional_detail::init_value_tag(), optional_detail::forward<T>(val)) optional ( rval_reference_type val ) : base(optional_detail::init_value_tag(), optional_detail::forward_<T>(val))
{} {}
// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional.
@@ -684,7 +651,7 @@ class optional
/// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. /// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional.
// Can throw if T::T(T &&) does // Can throw if T::T(T &&) does
optional ( bool cond, rval_reference_type val ) : base( cond, optional_detail::forward<T>(val) ) optional ( bool cond, rval_reference_type val ) : base( cond, optional_detail::forward_<T>(val) )
{} {}
// NOTE: MSVC needs templated versions first // NOTE: MSVC needs templated versions first
@@ -718,7 +685,7 @@ class optional
base() base()
{ {
if ( rhs.is_initialized() ) if ( rhs.is_initialized() )
this->construct( optional_detail::move(rhs.get()) ); this->construct( optional_detail::move_(rhs.get()) );
} }
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
@@ -737,7 +704,7 @@ class optional
explicit optional ( Expr&& expr, explicit optional ( Expr&& expr,
BOOST_DEDUCED_TYPENAME boost::enable_if< optional_detail::is_optional_val_init_candidate<T, Expr>, bool>::type = true BOOST_DEDUCED_TYPENAME boost::enable_if< optional_detail::is_optional_val_init_candidate<T, Expr>, bool>::type = true
) )
: base(optional_detail::forward<Expr>(expr),boost::addressof(expr)) : base(optional_detail::forward_<Expr>(expr),boost::addressof(expr))
{} {}
#endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT #endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
@@ -757,7 +724,7 @@ class optional
#else #else
optional ( optional && rhs ) optional ( optional && rhs )
BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value) BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value)
: base( optional_detail::move(rhs) ) : base( optional_detail::move_(rhs) )
{} {}
#endif #endif
@@ -776,7 +743,7 @@ class optional
BOOST_DEDUCED_TYPENAME boost::enable_if<optional_detail::is_optional_val_assign_candidate<T, Expr>, optional&>::type BOOST_DEDUCED_TYPENAME boost::enable_if<optional_detail::is_optional_val_assign_candidate<T, Expr>, optional&>::type
operator= ( Expr&& expr ) operator= ( Expr&& expr )
{ {
this->assign_expr(optional_detail::forward<Expr>(expr),boost::addressof(expr)); this->assign_expr(optional_detail::forward_<Expr>(expr),boost::addressof(expr));
return *this ; return *this ;
} }
@@ -798,7 +765,7 @@ class optional
template<class U> template<class U>
optional& operator= ( optional<U> && rhs ) optional& operator= ( optional<U> && rhs )
{ {
this->assign(optional_detail::move(rhs)); this->assign(optional_detail::move_(rhs));
return *this ; return *this ;
} }
@@ -834,7 +801,7 @@ class optional
BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_same<T, BOOST_DEDUCED_TYPENAME boost::decay<T_>::type>, optional&>::type BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_same<T, BOOST_DEDUCED_TYPENAME boost::decay<T_>::type>, optional&>::type
operator= ( T_&& val ) operator= ( T_&& val )
{ {
this->assign( optional_detail::forward<T_>(val) ) ; this->assign( optional_detail::forward_<T_>(val) ) ;
return *this ; return *this ;
} }
@@ -851,7 +818,7 @@ class optional
// Assigns from a T (deep-moves the rhs value) // Assigns from a T (deep-moves the rhs value)
optional& operator= ( rval_reference_type val ) optional& operator= ( rval_reference_type val )
{ {
this->assign( optional_detail::move(val) ) ; this->assign( optional_detail::move_(val) ) ;
return *this ; return *this ;
} }
@@ -871,17 +838,17 @@ class optional
template<class... Args> template<class... Args>
void emplace ( Args&&... args ) void emplace ( Args&&... args )
{ {
this->emplace_assign( optional_detail::forward<Args>(args)... ); this->emplace_assign( optional_detail::forward_<Args>(args)... );
} }
template<class... Args> template<class... Args>
explicit optional ( in_place_init_t, Args&&... args ) explicit optional ( in_place_init_t, Args&&... args )
: base( in_place_init, optional_detail::forward<Args>(args)... ) : base( in_place_init, optional_detail::forward_<Args>(args)... )
{} {}
template<class... Args> template<class... Args>
explicit optional ( in_place_init_if_t, bool cond, Args&&... args ) explicit optional ( in_place_init_if_t, bool cond, Args&&... args )
: base( in_place_init_if, cond, optional_detail::forward<Args>(args)... ) : base( in_place_init_if, cond, optional_detail::forward_<Args>(args)... )
{} {}
void swap( optional & arg ) void swap( optional & arg )
@@ -915,7 +882,7 @@ class optional
reference_type operator *() BOOST_OPTIONAL_REF_QUAL { return this->get() ; } reference_type operator *() BOOST_OPTIONAL_REF_QUAL { return this->get() ; }
#ifndef BOOST_NO_CXX11_REF_QUALIFIERS #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
reference_type_of_temporary_wrapper operator *() && { return optional_detail::move(this->get()) ; } reference_type_of_temporary_wrapper operator *() && { return optional_detail::move_(this->get()) ; }
#endif #endif
reference_const_type value() BOOST_OPTIONAL_CONST_REF_QUAL reference_const_type value() BOOST_OPTIONAL_CONST_REF_QUAL
@@ -940,7 +907,7 @@ class optional
if (this->is_initialized()) if (this->is_initialized())
return get(); return get();
else else
return optional_detail::forward<U>(v); return optional_detail::forward_<U>(v);
} }
template <typename F> template <typename F>
@@ -956,7 +923,7 @@ class optional
reference_type_of_temporary_wrapper value() && reference_type_of_temporary_wrapper value() &&
{ {
if (this->is_initialized()) if (this->is_initialized())
return optional_detail::move(this->get()) ; return optional_detail::move_(this->get()) ;
else else
throw_exception(bad_optional_access()); throw_exception(bad_optional_access());
} }
@@ -965,16 +932,16 @@ class optional
value_type value_or ( U&& v ) && value_type value_or ( U&& v ) &&
{ {
if (this->is_initialized()) if (this->is_initialized())
return optional_detail::move(get()); return optional_detail::move_(get());
else else
return optional_detail::forward<U>(v); return optional_detail::forward_<U>(v);
} }
template <typename F> template <typename F>
value_type value_or_eval ( F f ) && value_type value_or_eval ( F f ) &&
{ {
if (this->is_initialized()) if (this->is_initialized())
return optional_detail::move(get()); return optional_detail::move_(get());
else else
return f(); return f();
} }
@@ -1005,7 +972,7 @@ class optional
optional<typename optional_detail::result_of<F, reference_type_of_temporary_wrapper>::type> map(F f) && optional<typename optional_detail::result_of<F, reference_type_of_temporary_wrapper>::type> map(F f) &&
{ {
if (this->has_value()) if (this->has_value())
return f(optional_detail::move(this->get())); return f(optional_detail::move_(this->get()));
else else
return none; return none;
} }
@@ -1037,7 +1004,7 @@ class optional
flat_map(F f) && flat_map(F f) &&
{ {
if (this->has_value()) if (this->has_value())
return f(optional_detail::move(get())); return f(optional_detail::move_(get()));
else else
return none; return none;
} }
@@ -1048,128 +1015,34 @@ class optional
explicit operator bool() const BOOST_NOEXCEPT { return this->has_value() ; } explicit operator bool() const BOOST_NOEXCEPT { return this->has_value() ; }
} ; } ;
template<class T>
class optional<T&&>
{
static_assert(sizeof(T) == 0, "Optional rvalue references are illegal.");
} ;
} // namespace boost } // namespace boost
#include <boost/optional/detail/optional_swap.hpp>
#endif // pre-C++14 impl
namespace boost {
template <class T>
class optional<T&&>
{
static_assert(sizeof(T) == 0, "Optional rvalue references are illegal.");
};
}
#ifndef BOOST_OPTIONAL_CONFIG_DONT_SPECIALIZE_OPTIONAL_REFS #ifndef BOOST_OPTIONAL_CONFIG_DONT_SPECIALIZE_OPTIONAL_REFS
# include <boost/optional/detail/optional_reference_spec.hpp> # include <boost/optional/detail/optional_reference_spec.hpp>
#endif #endif
namespace boost { #include <boost/optional/detail/optional_hash.hpp>
template<class T>
inline
optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type> make_optional ( T && v )
{
return optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type>(optional_detail::forward<T>(v));
}
// Returns optional<T>(cond,v)
template<class T>
inline
optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type> make_optional ( bool cond, T && v )
{
return optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type>(cond,optional_detail::forward<T>(v));
}
// Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
// No-throw
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
get ( optional<T> const& opt )
{
return opt.get() ;
}
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::reference_type
get ( optional<T>& opt )
{
return opt.get() ;
}
// Returns a pointer to the value if this is initialized, otherwise, returns NULL.
// No-throw
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
get ( optional<T> const* opt )
{
return opt->get_ptr() ;
}
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
get ( optional<T>* opt )
{
return opt->get_ptr() ;
}
// Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
// No-throw
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
get_optional_value_or ( optional<T> const& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type v )
{
return opt.get_value_or(v) ;
}
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::reference_type
get_optional_value_or ( optional<T>& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_type v )
{
return opt.get_value_or(v) ;
}
// Returns a pointer to the value if this is initialized, otherwise, returns NULL.
// No-throw
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
get_pointer ( optional<T> const& opt )
{
return opt.get_ptr() ;
}
template<class T>
inline
BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
get_pointer ( optional<T>& opt )
{
return opt.get_ptr() ;
}
} // namespace boost
#ifndef BOOST_NO_IOSTREAM
namespace boost {
// The following declaration prevents a bug where operator safe-bool is used upon streaming optional object if you forget the IO header.
template<class CharType, class CharTrait>
std::basic_ostream<CharType, CharTrait>&
operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optional_tag const&)
{
static_assert(sizeof(CharType) == 0, "If you want to output boost::optional, include header <boost/optional/optional_io.hpp>");
return os;
}
} // namespace boost
#endif // BOOST_NO_IOSTREAM
#include <boost/optional/detail/optional_relops.hpp> #include <boost/optional/detail/optional_relops.hpp>
#include <boost/optional/detail/optional_swap.hpp> #include <boost/optional/detail/optional_nonmember_interface.hpp>
#endif // header guard #endif // header guard
+14 -4
View File
@@ -17,25 +17,35 @@
#define BOOST_OPTIONAL_OPTIONAL_FWD_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FWD_FLC_19NOV2002_HPP
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/core/invoke_swap.hpp>
#include <boost/optional/detail/optional_select_implementation.hpp>
#include <type_traits>
namespace boost { namespace boost {
template<class T> class optional ; template<class T> class optional ;
// This forward is needed to refer to namespace scope swap from the member swap // This forward is needed to refer to namespace scope swap from the member swap
template<class T> void swap ( optional<T>& , optional<T>& ) ; #ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
template<class T> BOOST_OPTIONAL_CXX20_CONSTEXPR void swap ( optional<T>& lhs, optional<T>& rhs )
noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*lhs, *rhs)));
#else
template<class T> void swap ( optional<T>& , optional<T>& ) ;
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
template<class T> struct optional_swap_should_use_default_constructor ; template<class T> struct optional_swap_should_use_default_constructor ;
#ifndef BOOST_OPTIONAL_CONFIG_DONT_SPECIALIZE_OPTIONAL_REFS #ifndef BOOST_OPTIONAL_CONFIG_DONT_SPECIALIZE_OPTIONAL_REFS
template<class T> class optional<T&> ; template<class T> class optional<T&> ;
template<class T> void swap ( optional<T&>& , optional<T&>& ) BOOST_NOEXCEPT; template<class T> BOOST_CXX14_CONSTEXPR void swap ( optional<T&>& , optional<T&>& ) BOOST_NOEXCEPT;
#endif #endif
} // namespace boost } // namespace boost
#endif #endif
+1 -1
View File
@@ -63,7 +63,7 @@ operator>>(std::basic_istream<CharType, CharTrait>& in, optional<T>& v)
{ {
T x; T x;
in >> x; in >> x;
v = optional_detail::move(x); v = optional_detail::move_(x);
} }
else else
{ {
+5 -1
View File
@@ -28,7 +28,6 @@ project
cxx11_explicit_conversion_operators cxx11_explicit_conversion_operators
# cxx11_noexcept # cxx11_noexcept
cxx11_rvalue_references cxx11_rvalue_references
cxx11_static_assert
cxx11_variadic_templates cxx11_variadic_templates
] ]
; ;
@@ -37,8 +36,11 @@ project
run optional_test.cpp : : : <library>/boost/bind//boost_bind ; run optional_test.cpp : : : <library>/boost/bind//boost_bind ;
run optional_test_assign.cpp ; run optional_test_assign.cpp ;
run optional_test_swap.cpp ; run optional_test_swap.cpp ;
compile optional_test_constexpr.cpp ;
compile optional_test_wuninitialized.cpp ; compile optional_test_wuninitialized.cpp ;
compile optional_test_fwd_header.cpp ;
run optional_test_conversions_from_U.cpp ; run optional_test_conversions_from_U.cpp ;
run optional_test_constructors.cpp ;
run optional_test_convert_from_T.cpp ; run optional_test_convert_from_T.cpp ;
run optional_test_convert_assign.cpp ; run optional_test_convert_assign.cpp ;
run optional_test_empty_braces.cpp ; run optional_test_empty_braces.cpp ;
@@ -47,6 +49,7 @@ run optional_test_flat_map.cpp ;
run optional_test_hash.cpp ; run optional_test_hash.cpp ;
run optional_test_map.cpp ; run optional_test_map.cpp ;
run optional_test_tie.cpp : : : <library>/boost/tuple//boost_tuple ; run optional_test_tie.cpp : : : <library>/boost/tuple//boost_tuple ;
run optional_test_ranges_find.cpp ;
run optional_test_ref_assign_portable_minimum.cpp ; run optional_test_ref_assign_portable_minimum.cpp ;
run optional_test_ref_assign_mutable_int.cpp ; run optional_test_ref_assign_mutable_int.cpp ;
run optional_test_ref_assign_const_int.cpp ; run optional_test_ref_assign_const_int.cpp ;
@@ -78,6 +81,7 @@ compile-fail optional_test_fail3b.cpp ;
compile-fail optional_test_ref_fail1.cpp ; compile-fail optional_test_ref_fail1.cpp ;
compile-fail optional_test_ref_fail3.cpp ; compile-fail optional_test_ref_fail3.cpp ;
compile-fail optional_test_ref_fail4.cpp ; compile-fail optional_test_ref_fail4.cpp ;
compile-fail optional_test_ref_fail_convert_from_temporary_optional_T.cpp ;
compile-fail optional_test_inplace_fail.cpp ; compile-fail optional_test_inplace_fail.cpp ;
compile-fail optional_test_inplace_fail2.cpp ; compile-fail optional_test_inplace_fail2.cpp ;
compile-fail optional_test_fail_implicit_bool_convert.cpp ; compile-fail optional_test_fail_implicit_bool_convert.cpp ;
+32
View File
@@ -0,0 +1,32 @@
// Copyright (C) 2021 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
template <typename U>
struct wrapper {};
template <typename /*Tag*/, typename U>
int get(wrapper<U> const&) { return 0; }
#include "boost/optional/optional.hpp"
namespace boost
{
struct any_type_in_boost_namespace {};
}
class tag; // user-defined tag
int main()
{
// the following tests if boost::get for optional<> does
// not interfere with the global get
return get<tag>(wrapper<boost::any_type_in_boost_namespace>());
}
+132
View File
@@ -0,0 +1,132 @@
// Copyright (C) 2026, Andrzej Krzemieński.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
#include "boost/optional.hpp"
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
struct Record
{
int i;
constexpr explicit Record(int i) : i(i) {}
constexpr int operator()() const { return i; }
};
struct Guard
{
int i;
constexpr explicit Guard(int i) : i(i) {}
Guard(Guard&&) = delete;
};
static_assert(boost::none == boost::none, "");
static_assert(!(boost::none != boost::none), "");
namespace test_int
{
constexpr boost::optional<int> oN;
static_assert(!oN, "");
static_assert(oN == boost::none, "");
static_assert(oN <= boost::none, "");
static_assert(!(oN != boost::none), "");
static_assert(oN == oN, "");
static_assert(!oN.has_value(), "");
static_assert(oN.value_or({}) == 0, "");
static_assert(oN.value_or(0) == 0, "");
static_assert(oN.value_or_eval(Record(9)) == 9, "");
constexpr boost::optional<int> o1 (1);
constexpr boost::optional<int> o2 {2};
static_assert(o1, "");
static_assert(o1.has_value(), "");
static_assert(o1 != boost::none, "");
static_assert(o1 != oN, "");
static_assert(o1 > oN, "");
static_assert(o1 >= oN, "");
static_assert(*o1 == 1, "");
static_assert(o1.value() == 1, "");
static_assert(o1.value_or(0) == 1, "");
static_assert(o1.value_or({}) == 1, "");
static_assert(o1.value_or_eval(Record(9)) == 1, "");
static_assert(o1 == 1, "");
static_assert(o2, "");
static_assert(o2 != o1, "");
static_assert(o2 > o1, "");
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
constexpr boost::optional<int> oNc = oN;
constexpr boost::optional<int> oNd = boost::none;
constexpr boost::optional<int> oNe = {};
static_assert(oNc == oN, "");
static_assert(oNd == oN, "");
static_assert(oNe == oN, "");
constexpr bool test_reset() {
boost::optional<int> o = 1;
assert(o);
o = boost::none;
assert(!o);
return o == boost::none;
}
static_assert(test_reset(), "");
#endif
}
namespace test_record
{
constexpr boost::optional<Record> rN (boost::none);
constexpr boost::optional<Record> r1 (Record(1));
constexpr boost::optional<Record> r2 (boost::in_place_init, 2);
static_assert(!rN, "");
static_assert(rN == boost::none, "");
static_assert(r1, "");
static_assert(r1 != boost::none, "");
static_assert(r2, "");
static_assert(rN.value_or(Record(9)).i == 9, "");
static_assert(r1->i == 1, "");
static_assert(r2.value().i == 2, "");
}
namespace test_guard
{
constexpr boost::optional<Guard> g1 {boost::in_place_init, 1};
constexpr boost::optional<Guard> gNa {boost::none};
constexpr boost::optional<Guard> gNb;
static_assert(g1, "");
static_assert(!!g1, "");
static_assert(g1 != boost::none, "");
static_assert(!(g1 == boost::none), "");
static_assert(g1.has_value(), "");
static_assert(!gNa, "");
static_assert(!gNa.has_value(), "");
static_assert(gNa == boost::none, "");
static_assert(!(gNa != boost::none), "");
static_assert(!gNb, "");
static_assert(!gNb.has_value(), "");
static_assert(gNb == boost::none, "");
static_assert(!(gNb != boost::none), "");
}
namespace test_optional_ref
{
constexpr int gi = 9;
constexpr boost::optional<const int&> iref = gi;
static_assert(iref, "");
static_assert(*iref == 9, "");
}
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
@@ -55,5 +55,6 @@ int main()
{ {
// Invokes boost::optional copy constructor. Should not invoke wrapper constructor from U. // Invokes boost::optional copy constructor. Should not invoke wrapper constructor from U.
boost::optional< wrapper< int > > res = foo(); boost::optional< wrapper< int > > res = foo();
(void)res;
return 0; return 0;
} }
+287
View File
@@ -0,0 +1,287 @@
// Copyright (C) 2026 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
#include "boost/optional/optional.hpp"
#include "boost/core/lightweight_test.hpp"
#include <string>
using boost::optional;
using boost::none;
struct MyBool
{
bool b;
MyBool (bool b) : b(b) {}
operator bool() const { return b; };
};
struct MyExplicitBool
{
bool b;
MyExplicitBool (bool b) : b(b) {}
operator bool() const { return b; };
};
struct Any
{
template <typename... T>
Any(T&&...) {}
};
struct JustCopyMoveCtor
{
JustCopyMoveCtor(JustCopyMoveCtor&&) = default;
JustCopyMoveCtor(JustCopyMoveCtor const&) = default;
JustCopyMoveCtor& operator=(JustCopyMoveCtor&&) = delete;
JustCopyMoveCtor& operator=(JustCopyMoveCtor const&) = delete;
JustCopyMoveCtor() = delete;
};
struct JustDefault
{
JustDefault() = default;
JustDefault(JustDefault&&) = delete;
};
template <typename T>
optional<T> empty_optional()
{
return optional<T>(); // this is to avoid "the most vexing parse"
}
template <typename T, typename U>
void direct_test_ctor_optional_T_from_empty_optional_T()
{
optional<U> om;
const optional<U> oc;
BOOST_TEST(!om);
BOOST_TEST(!oc);
{
optional<T> ox = om;
BOOST_TEST(!ox);
optional<T> oy = oc;
BOOST_TEST(!oy);
optional<T> oz = empty_optional<U>();
BOOST_TEST(!oz);
}
{
optional<T> ox = {om};
BOOST_TEST(!ox);
optional<T> oy = {oc};
BOOST_TEST(!oy);
optional<T> oz = {empty_optional<U>()};
BOOST_TEST(!oz);
}
{
optional<T> ox{om};
BOOST_TEST(!ox);
optional<T> oy{oc};
BOOST_TEST(!oy);
optional<T> oz{empty_optional<U>()};
BOOST_TEST(!oz);
}
{
optional<T> ox(om);
BOOST_TEST(!ox);
optional<T> oy(oc);
BOOST_TEST(!oy);
optional<T> oz(empty_optional<U>());
BOOST_TEST(!oz);
}
}
template <typename T, typename U>
void test_ctor_optional_T_from_empty_optional_T()
{
direct_test_ctor_optional_T_from_empty_optional_T<T, U>();
direct_test_ctor_optional_T_from_empty_optional_T<const T, const U>();
direct_test_ctor_optional_T_from_empty_optional_T<optional<T>, optional<U>>();
direct_test_ctor_optional_T_from_empty_optional_T<optional<const T>, optional<const U>>();
direct_test_ctor_optional_T_from_empty_optional_T<const optional<T>, const optional<U>>();
}
template <typename T, typename U>
void direct_test_ctor_optional_T_from_optional_U(U val)
{
optional<U> om;
const optional<U> oc;
BOOST_TEST(!om);
BOOST_TEST(!oc);
{
optional<T> ox{om};
BOOST_TEST(!ox);
optional<T> oy{oc};
BOOST_TEST(!oy);
optional<T> oz{empty_optional<U>()};
BOOST_TEST(!oz);
}
{
optional<T> ox(om);
BOOST_TEST(!ox);
optional<T> oy(oc);
BOOST_TEST(!oy);
optional<T> oz(empty_optional<U>());
BOOST_TEST(!oz);
}
{
optional<U> om {val};
const optional<U> oc {val};
{
optional<T> ox{om};
BOOST_TEST(ox);
optional<T> oy{oc};
BOOST_TEST(oy);
optional<T> oz{boost::make_optional(val)};
BOOST_TEST(oz);
}
{
optional<T> ox(om);
BOOST_TEST(ox);
optional<T> oy(oc);
BOOST_TEST(oy);
optional<T> oz(boost::make_optional(val));
BOOST_TEST(oz);
}
}
}
template <typename T, typename U>
void test_ctor_optional_T_from_optional_U(U val)
{
direct_test_ctor_optional_T_from_optional_U<T>(val);
}
template <typename T>
void direct_test_ctor_optional_T_from_valued_optional_T(T val)
{
optional<T> om(val);
const optional<T> oc(val);
BOOST_TEST(om);
BOOST_TEST(oc);
{
optional<T> ox = om;
BOOST_TEST(ox);
optional<T> oy = oc;
BOOST_TEST(oy);
optional<T> oz = optional<T>(val);
BOOST_TEST(oz);
}
{
optional<T> ox = {om};
BOOST_TEST(ox);
optional<T> oy = {oc};
BOOST_TEST(oy);
optional<T> oz = {optional<T>(val)};
BOOST_TEST(oz);
}
}
template <typename T>
void test_ctor_optional_T_from_valued_optional_T(T val)
{
direct_test_ctor_optional_T_from_valued_optional_T<T>(val);
direct_test_ctor_optional_T_from_valued_optional_T<optional<T>>(val);
direct_test_ctor_optional_T_from_valued_optional_T<const T>(val);
direct_test_ctor_optional_T_from_optional_U<T, T>(val);
direct_test_ctor_optional_T_from_optional_U<optional<T>, optional<T>>(val);
}
template <typename T>
void direct_test_inplace_tag_constructor()
{
{
optional<T> ox (boost::in_place_init);
BOOST_TEST(ox);
}
{
optional<T> ox {boost::in_place_init};
BOOST_TEST(ox);
}
}
template <typename T>
void test_inplace_tag_constructor()
{
direct_test_inplace_tag_constructor<T>();
direct_test_inplace_tag_constructor<optional<T>>();
}
int main()
{
test_ctor_optional_T_from_empty_optional_T<int, int>();
test_ctor_optional_T_from_empty_optional_T<long, long>();
test_ctor_optional_T_from_empty_optional_T<std::string, std::string>();
test_ctor_optional_T_from_empty_optional_T<JustCopyMoveCtor, JustCopyMoveCtor>();
test_ctor_optional_T_from_empty_optional_T<MyBool, MyBool>();
test_ctor_optional_T_from_empty_optional_T<MyExplicitBool, MyExplicitBool>();
test_ctor_optional_T_from_empty_optional_T<bool, bool>();
test_ctor_optional_T_from_empty_optional_T<Any, Any>();
test_inplace_tag_constructor<int>();
test_inplace_tag_constructor<Any>();
test_inplace_tag_constructor<JustDefault>();
test_ctor_optional_T_from_optional_U<int>(1);
test_ctor_optional_T_from_optional_U<long>(1);
test_ctor_optional_T_from_optional_U<bool>(MyBool{true});
test_ctor_optional_T_from_optional_U<bool>(MyBool{false});
test_ctor_optional_T_from_optional_U<MyBool>(true);
test_ctor_optional_T_from_optional_U<MyBool>(false);
test_ctor_optional_T_from_optional_U<bool>(MyExplicitBool{true});
test_ctor_optional_T_from_optional_U<bool>(MyExplicitBool{false});
test_ctor_optional_T_from_optional_U<MyExplicitBool>(true);
test_ctor_optional_T_from_optional_U<MyExplicitBool>(false);
test_ctor_optional_T_from_optional_U<Any>(true);
test_ctor_optional_T_from_optional_U<Any>(Any{});
test_ctor_optional_T_from_valued_optional_T(1);
optional<MyBool> ob;
optional<bool> oa;
oa = ob;
BOOST_TEST(!oa);
return boost::report_errors();
}
+1
View File
@@ -13,6 +13,7 @@
#include "boost/core/lightweight_test.hpp" #include "boost/core/lightweight_test.hpp"
#include "boost/none.hpp" #include "boost/none.hpp"
#include "boost/type_traits/is_assignable.hpp"
//#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR //#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR
+2
View File
@@ -45,6 +45,8 @@ void test_optional_of_superconverting_T() // compile-time test
superconv<optional<int> > s; superconv<optional<int> > s;
superconv<optional<int> > & rs = s; superconv<optional<int> > & rs = s;
optional<superconv<optional<int> > > os = rs; optional<superconv<optional<int> > > os = rs;
(void)s;
(void)os;
#endif #endif
} }
@@ -29,4 +29,3 @@ void test_implicit_conversion_to_bool()
boost::optional<T> opt; boost::optional<T> opt;
opt.value_or(U()); opt.value_or(U());
} }
+23
View File
@@ -0,0 +1,23 @@
// Copyright (C) 2026 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
#include "boost/optional/optional_fwd.hpp"
#include "boost/optional/optional.hpp"
void statically_test_basic_instantiations()
{
boost::optional<int> oN, o1(1);
swap(oN, o1);
int i = 1;
boost::optional<int> rN, ri(i);
swap(rN, ri);
}
+33
View File
@@ -105,9 +105,42 @@ void test_assign()
#endif #endif
} }
// begin Boost.Log case
template <typename CharT>
struct basic_formatter
{
template< typename FunT >
basic_formatter(FunT&&) {}
template< typename FunT >
basic_formatter& operator= (FunT&&)
{
return *this;
}
};
template< typename CharT>
struct chained_formatter
{
};
void test_boost_log_case()
{
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
boost::optional<basic_formatter<char>> of( boost::in_place(chained_formatter<char>()) );
of = boost::in_place(chained_formatter<char>());
#endif //BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
}
// end Boost.Log case
int main() int main()
{ {
test_ctor(); test_ctor();
test_assign(); test_assign();
test_boost_log_case();
return boost::report_errors(); return boost::report_errors();
} }
+36 -36
View File
@@ -75,13 +75,13 @@ void test_move_ctor_from_U()
optional<Oracle> o1 ((OracleVal())); optional<Oracle> o1 ((OracleVal()));
BOOST_TEST(o1); BOOST_TEST(o1);
BOOST_TEST(o1->s == sValueMoveConstructed || o1->s == sMoveConstructed); BOOST_TEST(o1->s == sValueMoveConstructed || o1->s == sMoveConstructed);
OracleVal v1; OracleVal v1;
optional<Oracle> o2 (v1); optional<Oracle> o2 (v1);
BOOST_TEST(o2); BOOST_TEST(o2);
BOOST_TEST(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed ); BOOST_TEST(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed );
BOOST_TEST(v1.s == sIntConstructed); BOOST_TEST(v1.s == sIntConstructed);
optional<Oracle> o3 (std::move(v1)); optional<Oracle> o3 (std::move(v1));
BOOST_TEST(o3); BOOST_TEST(o3);
BOOST_TEST(o3->s == sValueMoveConstructed || o3->s == sMoveConstructed); BOOST_TEST(o3->s == sValueMoveConstructed || o3->s == sMoveConstructed);
@@ -93,13 +93,13 @@ void test_move_ctor_form_T()
optional<Oracle> o1 ((Oracle())); optional<Oracle> o1 ((Oracle()));
BOOST_TEST(o1); BOOST_TEST(o1);
BOOST_TEST(o1->s == sMoveConstructed); BOOST_TEST(o1->s == sMoveConstructed);
Oracle v1; Oracle v1;
optional<Oracle> o2 (v1); optional<Oracle> o2 (v1);
BOOST_TEST(o2); BOOST_TEST(o2);
BOOST_TEST(o2->s == sCopyConstructed); BOOST_TEST(o2->s == sCopyConstructed);
BOOST_TEST(v1.s == sDefaultConstructed); BOOST_TEST(v1.s == sDefaultConstructed);
optional<Oracle> o3 (std::move(v1)); optional<Oracle> o3 (std::move(v1));
BOOST_TEST(o3); BOOST_TEST(o3);
BOOST_TEST(o3->s == sMoveConstructed); BOOST_TEST(o3->s == sMoveConstructed);
@@ -110,24 +110,24 @@ void test_move_ctor_from_optional_T()
{ {
optional<Oracle> o1; optional<Oracle> o1;
optional<Oracle> o2(std::move(o1)); optional<Oracle> o2(std::move(o1));
BOOST_TEST(!o1); BOOST_TEST(!o1);
BOOST_TEST(!o2); BOOST_TEST(!o2);
optional<Oracle> o3((Oracle())); optional<Oracle> o3((Oracle()));
optional<Oracle> o4(std::move(o3)); optional<Oracle> o4(std::move(o3));
BOOST_TEST(o3); BOOST_TEST(o3);
BOOST_TEST(o4); BOOST_TEST(o4);
BOOST_TEST(o3->s == sMovedFrom); BOOST_TEST(o3->s == sMovedFrom);
BOOST_TEST(o4->s == sMoveConstructed); BOOST_TEST(o4->s == sMoveConstructed);
optional<Oracle> o5((optional<Oracle>())); optional<Oracle> o5((optional<Oracle>()));
BOOST_TEST(!o5); BOOST_TEST(!o5);
optional<Oracle> o6((optional<Oracle>(Oracle()))); optional<Oracle> o6((optional<Oracle>(Oracle())));
BOOST_TEST(o6); BOOST_TEST(o6);
BOOST_TEST(o6->s == sMoveConstructed); BOOST_TEST(o6->s == sMoveConstructed);
optional<Oracle> o7(o6); // does copy ctor from non-const lvalue compile? optional<Oracle> o7(o6); // does copy ctor from non-const lvalue compile?
} }
@@ -137,13 +137,13 @@ void test_move_assign_from_U()
o1 = boost::none; // test if additional assignments didn't break it o1 = boost::none; // test if additional assignments didn't break it
o1 = OracleVal(); o1 = OracleVal();
BOOST_TEST(o1); BOOST_TEST(o1);
BOOST_TEST(o1->s == sValueMoveConstructed); BOOST_TEST(o1->s == sValueMoveConstructed);
o1 = OracleVal(); o1 = OracleVal();
BOOST_TEST(o1); BOOST_TEST(o1);
BOOST_TEST(o1->s == sMoveAssigned); BOOST_TEST(o1->s == sMoveAssigned || o1->s == sValueMoveAssigned);
OracleVal v1; OracleVal v1;
optional<Oracle> o2; optional<Oracle> o2;
o2 = v1; o2 = v1;
@@ -152,9 +152,9 @@ void test_move_assign_from_U()
BOOST_TEST(v1.s == sIntConstructed); BOOST_TEST(v1.s == sIntConstructed);
o2 = v1; o2 = v1;
BOOST_TEST(o2); BOOST_TEST(o2);
BOOST_TEST(o2->s == sCopyAssigned || o2->s == sMoveAssigned); BOOST_TEST(o2->s == sCopyAssigned || o2->s == sMoveAssigned || o2->s == sValueCopyAssigned);
BOOST_TEST(v1.s == sIntConstructed); BOOST_TEST(v1.s == sIntConstructed);
optional<Oracle> o3; optional<Oracle> o3;
o3 = std::move(v1); o3 = std::move(v1);
BOOST_TEST(o3); BOOST_TEST(o3);
@@ -167,12 +167,12 @@ void test_move_assign_from_T()
optional<Oracle> o1; optional<Oracle> o1;
o1 = Oracle(); o1 = Oracle();
BOOST_TEST(o1); BOOST_TEST(o1);
BOOST_TEST(o1->s == sMoveConstructed); BOOST_TEST(o1->s == sMoveConstructed);
o1 = Oracle(); o1 = Oracle();
BOOST_TEST(o1); BOOST_TEST(o1);
BOOST_TEST(o1->s == sMoveAssigned); BOOST_TEST(o1->s == sMoveAssigned);
Oracle v1; Oracle v1;
optional<Oracle> o2; optional<Oracle> o2;
o2 = v1; o2 = v1;
@@ -183,7 +183,7 @@ void test_move_assign_from_T()
BOOST_TEST(o2); BOOST_TEST(o2);
BOOST_TEST(o2->s == sCopyAssigned); BOOST_TEST(o2->s == sCopyAssigned);
BOOST_TEST(v1.s == sDefaultConstructed); BOOST_TEST(v1.s == sDefaultConstructed);
optional<Oracle> o3; optional<Oracle> o3;
o3 = std::move(v1); o3 = std::move(v1);
BOOST_TEST(o3); BOOST_TEST(o3);
@@ -203,13 +203,13 @@ void test_move_assign_from_optional_T()
BOOST_TEST(o3->s == sMoveConstructed); BOOST_TEST(o3->s == sMoveConstructed);
BOOST_TEST(o1); BOOST_TEST(o1);
BOOST_TEST(o1->s == sCopyConstructed); BOOST_TEST(o1->s == sCopyConstructed);
o2 = std::move(o3); o2 = std::move(o3);
BOOST_TEST(o3); BOOST_TEST(o3);
BOOST_TEST(o3->s == sMovedFrom); BOOST_TEST(o3->s == sMovedFrom);
BOOST_TEST(o2); BOOST_TEST(o2);
BOOST_TEST(o2->s == sMoveConstructed); BOOST_TEST(o2->s == sMoveConstructed);
o2 = optional<Oracle>((Oracle())); o2 = optional<Oracle>((Oracle()));
BOOST_TEST(o2); BOOST_TEST(o2);
BOOST_TEST(o2->s == sMoveAssigned); BOOST_TEST(o2->s == sMoveAssigned);
@@ -222,11 +222,11 @@ public:
MoveOnly(int v) : val(v) {} MoveOnly(int v) : val(v) {}
MoveOnly(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; } MoveOnly(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; }
void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; } void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; }
private: private:
MoveOnly(MoveOnly const&); MoveOnly(MoveOnly const&);
void operator=(MoveOnly const&); void operator=(MoveOnly const&);
friend class MoveOnlyB; friend class MoveOnlyB;
}; };
@@ -243,7 +243,7 @@ void test_with_move_only()
BOOST_TEST(o4->val == 1); BOOST_TEST(o4->val == 1);
BOOST_TEST(o2); BOOST_TEST(o2);
BOOST_TEST(o2->val == 0); BOOST_TEST(o2->val == 0);
o3 = std::move(o4); o3 = std::move(o4);
BOOST_TEST(o3); BOOST_TEST(o3);
BOOST_TEST(o3->val == 1); BOOST_TEST(o3->val == 1);
@@ -260,7 +260,7 @@ public:
void operator=(MoveOnlyB&& rhs) {val = rhs.val; rhs.val = 0; } void operator=(MoveOnlyB&& rhs) {val = rhs.val; rhs.val = 0; }
MoveOnlyB(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; } MoveOnlyB(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; }
void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; } void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; }
private: private:
MoveOnlyB(MoveOnlyB const&); MoveOnlyB(MoveOnlyB const&);
void operator=(MoveOnlyB const&); void operator=(MoveOnlyB const&);
@@ -273,14 +273,14 @@ void test_move_assign_from_optional_U()
optional<MoveOnly> a((MoveOnly(2))); optional<MoveOnly> a((MoveOnly(2)));
optional<MoveOnlyB> b1; optional<MoveOnlyB> b1;
b1 = std::move(a); b1 = std::move(a);
BOOST_TEST(b1); BOOST_TEST(b1);
BOOST_TEST(b1->val == 2); BOOST_TEST(b1->val == 2);
BOOST_TEST(a); BOOST_TEST(a);
BOOST_TEST(a->val == 0); BOOST_TEST(a->val == 0);
b1 = MoveOnly(4); b1 = MoveOnly(4);
BOOST_TEST(b1); BOOST_TEST(b1);
BOOST_TEST(b1->val == 4); BOOST_TEST(b1->val == 4);
} }
@@ -289,14 +289,14 @@ void test_move_ctor_from_optional_U()
{ {
optional<MoveOnly> a((MoveOnly(2))); optional<MoveOnly> a((MoveOnly(2)));
optional<MoveOnlyB> b1(std::move(a)); optional<MoveOnlyB> b1(std::move(a));
BOOST_TEST(b1); BOOST_TEST(b1);
BOOST_TEST(b1->val == 2); BOOST_TEST(b1->val == 2);
BOOST_TEST(a); BOOST_TEST(a);
BOOST_TEST(a->val == 0); BOOST_TEST(a->val == 0);
optional<MoveOnlyB> b2(( optional<MoveOnly>(( MoveOnly(4) )) )); optional<MoveOnlyB> b2(( optional<MoveOnly>(( MoveOnly(4) )) ));
BOOST_TEST(b2); BOOST_TEST(b2);
BOOST_TEST(b2->val == 4); BOOST_TEST(b2->val == 4);
} }
@@ -306,7 +306,7 @@ void test_swap()
optional<MoveOnly> a((MoveOnly(2))); optional<MoveOnly> a((MoveOnly(2)));
optional<MoveOnly> b((MoveOnly(3))); optional<MoveOnly> b((MoveOnly(3)));
swap(a, b); swap(a, b);
BOOST_TEST(a->val == 3); BOOST_TEST(a->val == 3);
BOOST_TEST(b->val == 2); BOOST_TEST(b->val == 2);
} }
@@ -317,12 +317,12 @@ void test_optional_ref_to_movables()
optional<MoveOnly&> orm = m; optional<MoveOnly&> orm = m;
orm->val = 2; orm->val = 2;
BOOST_TEST(m.val == 2); BOOST_TEST(m.val == 2);
optional<MoveOnly&> orm2 = orm; optional<MoveOnly&> orm2 = orm;
orm2->val = 1; orm2->val = 1;
BOOST_TEST(m.val == 1); BOOST_TEST(m.val == 1);
BOOST_TEST(orm->val == 1); BOOST_TEST(orm->val == 1);
optional<MoveOnly&> orm3 = std::move(orm); optional<MoveOnly&> orm3 = std::move(orm);
orm3->val = 4; orm3->val = 4;
BOOST_TEST(m.val == 4); BOOST_TEST(m.val == 4);
@@ -32,6 +32,7 @@ void test()
//BOOST_TEST(v); //BOOST_TEST(v);
boost::optional<boost::optional<int>> vv; boost::optional<boost::optional<int>> vv;
bool xx = vv?true : false; bool xx = vv?true : false;
(void)xx;
BOOST_TEST_EQ(*v, 7); BOOST_TEST_EQ(*v, 7);
#endif #endif
} }
+3
View File
@@ -11,6 +11,9 @@
#include "boost/optional/optional.hpp" #include "boost/optional/optional.hpp"
#include "boost/core/enable_if.hpp"
#include "boost/type_traits/is_constructible.hpp"
#ifdef BOOST_BORLANDC #ifdef BOOST_BORLANDC
#pragma hdrstop #pragma hdrstop
#endif #endif
+70
View File
@@ -0,0 +1,70 @@
// Copyright (C) 2026 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
#include "boost/optional/optional.hpp"
#include "boost/core/lightweight_test.hpp"
#include <type_traits>
#ifndef BOOST_NO_CXX20_HDR_RANGES
#include <ranges>
#include <concepts>
#include <iterator>
#include <array>
#include <string>
static_assert(std::equality_comparable<boost::none_t>, "boost::none shall be equality comparable");
template <typename T>
void test_that_you_can_find_none_in_a_range_of_optional(T x, T y)
{
static_assert(std::equality_comparable_with<boost::optional<T>, boost::none_t>, "boost::none shall satisfy the concept");
static_assert(std::equality_comparable_with<boost::none_t, boost::optional<T> >, "boost::none shall satisfy the concept");
static_assert(std::indirect_binary_predicate<std::ranges::equal_to, const boost::optional<T>*, const boost::none_t*>, "boost::none shall satisfy the concept");
// [0] [1] [2]
std::array<boost::optional<T>, 3> arr = {{ x, boost::none, y }};
auto it = std::ranges::find(arr, boost::none);
BOOST_TEST_EQ(std::distance(arr.begin(), it), 1);
}
#endif // BOOST_NO_CXX20_HDR_RANGES
# if (defined __GNUC__) && (!defined BOOST_INTEL_CXX_VERSION) && (!defined __clang__)
# if (__GNUC__ <= 4)
# define BOOST_OPTIONAL_TEST_INSUFFICIENT_TYPE_TRAIT_SUPPORT
# endif
# endif
#ifndef BOOST_OPTIONAL_TEST_INSUFFICIENT_TYPE_TRAIT_SUPPORT
static_assert(std::is_trivially_copyable<boost::none_t>::value, "boost::none shall be trivially copyable");
#endif
void test_that_none_is_equal_to_none()
{
BOOST_TEST(boost::none == boost::none);
BOOST_TEST(!(boost::none != boost::none));
auto None = boost::none;
BOOST_TEST(None == boost::none);
BOOST_TEST(!(None != boost::none));
}
int main()
{
#ifndef BOOST_NO_CXX20_HDR_RANGES
test_that_you_can_find_none_in_a_range_of_optional(1, 2);
test_that_you_can_find_none_in_a_range_of_optional<std::string>("one", "two");
#endif
test_that_none_is_equal_to_none();
return boost::report_errors();
}
@@ -0,0 +1,21 @@
// Copyright (C) 2003, Fernando Luis Cacciola Carballal.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void optional_reference__test_no_converting_initialization()
{
boost::optional<const int&> o (boost::optional<int>(1));
(void)o;
}
+121 -14
View File
@@ -24,7 +24,13 @@ using boost::none;
struct Value struct Value
{ {
int val; int val;
explicit Value(int v) : val(v) {} BOOST_CONSTEXPR explicit Value(int v) : val(v) {}
};
struct Guard
{
int val;
BOOST_CONSTEXPR explicit Guard(int v) : val(v) {}
}; };
int val(int const& i) int val(int const& i)
@@ -37,6 +43,11 @@ int val(Value const& v)
return v.val; return v.val;
} }
int val(Guard const& v)
{
return v.val;
}
template <typename Tref> template <typename Tref>
optional<Tref&> make_opt_ref(Tref& v) optional<Tref&> make_opt_ref(Tref& v)
{ {
@@ -47,21 +58,21 @@ template <typename Tval, typename Tref>
void test_construct_from_optional_ref() void test_construct_from_optional_ref()
{ {
Tref v1 (1), v2 (2); Tref v1 (1), v2 (2);
optional<Tref&> opt_ref0; optional<Tref&> opt_ref0;
optional<Tref&> opt_ref1 (v1); optional<Tref&> opt_ref1 (v1);
optional<Tval> opt_val0 (opt_ref0); optional<Tval> opt_val0 (opt_ref0);
optional<Tval> opt_val1 (opt_ref1); optional<Tval> opt_val1 (opt_ref1);
optional<Tval> opt_val2 (make_opt_ref(v2)); optional<Tval> opt_val2 (make_opt_ref(v2));
BOOST_TEST (!opt_val0); BOOST_TEST (!opt_val0);
BOOST_TEST (opt_val1); BOOST_TEST (opt_val1);
BOOST_TEST (opt_val2); BOOST_TEST (opt_val2);
BOOST_TEST_EQ (1, val(*opt_val1)); BOOST_TEST_EQ (1, val(*opt_val1));
BOOST_TEST_EQ (2, val(*opt_val2)); BOOST_TEST_EQ (2, val(*opt_val2));
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1)); BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2)); BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2));
} }
@@ -70,29 +81,121 @@ template <typename Tval, typename Tref>
void test_assign_from_optional_ref() void test_assign_from_optional_ref()
{ {
Tref v1 (1), v2 (2); Tref v1 (1), v2 (2);
optional<Tref&> opt_ref0; optional<Tref&> opt_ref0;
optional<Tref&> opt_ref1 (v1); optional<Tref&> opt_ref1 (v1);
optional<Tval> opt_val0; optional<Tval> opt_val0;
optional<Tval> opt_val1; optional<Tval> opt_val1;
optional<Tval> opt_val2; optional<Tval> opt_val2;
opt_val0 = opt_ref0; opt_val0 = opt_ref0;
opt_val1 = opt_ref1; opt_val1 = opt_ref1;
opt_val2 = make_opt_ref(v2); opt_val2 = make_opt_ref(v2);
BOOST_TEST (!opt_val0); BOOST_TEST (!opt_val0);
BOOST_TEST (opt_val1); BOOST_TEST (opt_val1);
BOOST_TEST (opt_val2); BOOST_TEST (opt_val2);
BOOST_TEST_EQ (1, val(*opt_val1)); BOOST_TEST_EQ (1, val(*opt_val1));
BOOST_TEST_EQ (2, val(*opt_val2)); BOOST_TEST_EQ (2, val(*opt_val2));
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1)); BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2)); BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2));
} }
template <typename T>
void test_convert_optional_T_to_optional_T_ref()
{
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
using boost::optional;
using boost::in_place_init;
{ // optional<T>& -> optional<T&>
optional<T> ovN, ov1(in_place_init, 1), ov2(in_place_init, 2);
optional<T&> orN = ovN;
optional<T&> or1 = ov1;
optional<T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
{ // const optional<T>& -> optional<const T&>
constexpr optional<T> ovN;
constexpr optional<T> ov1(in_place_init, 1);
constexpr optional<T> ov2(in_place_init, 2);
optional<const T&> orN = ovN;
optional<const T&> or1 = ov1;
optional<const T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
{ // optional<const T>& -> optional<const T&>
optional<const T> ovN;
optional<const T> ov1(in_place_init, 1);
optional<const T> ov2(in_place_init, 2);
optional<const T&> orN = ovN;
optional<const T&> or1 = ov1;
optional<const T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
{ // optional<T>& -> optional<const T&>
optional<T> ovN;
optional<T> ov1(in_place_init, 1);
optional<T> ov2(in_place_init, 2);
optional<const T&> orN = ovN;
optional<const T&> or1 = ov1;
optional<const T&> or2 = ov2;
BOOST_TEST_EQ (!!orN, !!ovN);
BOOST_TEST_EQ (!!or1, !!ov1);
BOOST_TEST_EQ (!!or2, !!ov2);
BOOST_TEST (or1);
BOOST_TEST (or2);
BOOST_TEST_EQ (val(*or1), 1);
BOOST_TEST_EQ (val(*or2), 2);
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
}
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
}
int main() int main()
{ {
@@ -100,17 +203,21 @@ int main()
test_construct_from_optional_ref<int, int const>(); test_construct_from_optional_ref<int, int const>();
test_construct_from_optional_ref<int const, int const>(); test_construct_from_optional_ref<int const, int const>();
test_construct_from_optional_ref<int const, int>(); test_construct_from_optional_ref<int const, int>();
test_construct_from_optional_ref<Value, Value>(); test_construct_from_optional_ref<Value, Value>();
test_construct_from_optional_ref<Value, Value const>(); test_construct_from_optional_ref<Value, Value const>();
test_construct_from_optional_ref<Value const, Value const>(); test_construct_from_optional_ref<Value const, Value const>();
test_construct_from_optional_ref<Value const, Value>(); test_construct_from_optional_ref<Value const, Value>();
test_assign_from_optional_ref<int, int>(); test_assign_from_optional_ref<int, int>();
test_assign_from_optional_ref<int, int const>(); test_assign_from_optional_ref<int, int const>();
test_assign_from_optional_ref<Value, Value>(); test_assign_from_optional_ref<Value, Value>();
test_assign_from_optional_ref<Value, Value const>(); test_assign_from_optional_ref<Value, Value const>();
test_convert_optional_T_to_optional_T_ref<int>();
test_convert_optional_T_to_optional_T_ref<Value>();
test_convert_optional_T_to_optional_T_ref<Guard>();
return boost::report_errors(); return boost::report_errors();
} }
+2 -1
View File
@@ -1,4 +1,4 @@
// Copyright (C) 2014 Andrzej Krzemienski. // Copyright (C) 2014, 2026 Andrzej Krzemienski.
// //
// Use, modification, and distribution is subject to the Boost Software // Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -9,6 +9,7 @@
// You are welcome to contact the author at: // You are welcome to contact the author at:
// akrzemi1@gmail.com // akrzemi1@gmail.com
#include <boost/type_traits/is_constructible.hpp>
#include "boost/optional/optional.hpp" #include "boost/optional/optional.hpp"
#ifdef BOOST_BORLANDC #ifdef BOOST_BORLANDC
+4
View File
@@ -20,6 +20,7 @@
#include "boost/type_traits/is_base_of.hpp" #include "boost/type_traits/is_base_of.hpp"
#include "boost/optional/detail/experimental_traits.hpp" #include "boost/optional/detail/experimental_traits.hpp"
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS #ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
struct PrivDefault struct PrivDefault
@@ -135,12 +136,15 @@ void test_trivial_copyability()
} }
#endif #endif
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
int main() int main()
{ {
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS #ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
test_type_traits(); test_type_traits();
test_trivial_copyability(); test_trivial_copyability();
#endif
#endif #endif
return boost::report_errors(); return boost::report_errors();
} }
+8 -3
View File
@@ -210,6 +210,7 @@ namespace boost {
// Compile time tweaking on whether or not swap should use the default constructor: // Compile time tweaking on whether or not swap should use the default constructor:
// //
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
template <> struct optional_swap_should_use_default_constructor< template <> struct optional_swap_should_use_default_constructor<
optional_swap_test::class_whose_default_ctor_should_be_used> : true_type {} ; optional_swap_test::class_whose_default_ctor_should_be_used> : true_type {} ;
@@ -218,7 +219,7 @@ template <> struct optional_swap_should_use_default_constructor<
template <class T> struct optional_swap_should_use_default_constructor< template <class T> struct optional_swap_should_use_default_constructor<
optional_swap_test::template_whose_default_ctor_should_be_used<T> > : true_type {} ; optional_swap_test::template_whose_default_ctor_should_be_used<T> > : true_type {} ;
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
// //
// Specialization of boost::swap: // Specialization of boost::swap:
@@ -352,15 +353,19 @@ void test_swap_member_function( T const* )
void test_swap_tweaking() void test_swap_tweaking()
{ {
( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) ); ( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) );
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) );
( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) );
( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) ); ( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) );
#endif
( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) ); ( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) );
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) );
( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) );
( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) ); ( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) );
#endif
} }
int main() int main()