Compare commits

...

17 Commits

Author SHA1 Message Date
Andrzej Krzemienski 8bc4a16933 Merge branch 'develop' 2026-02-27 14:04:53 +01: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 aaabe89a69 Merge branch 'develop' 2026-02-20 16:16:26 +01: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 d46b9c3f77 Merge branch 'develop' 2026-02-17 16:31:45 +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 881bf8da26 Merge branch 'develop' 2026-01-31 22:49:43 +01:00
34 changed files with 933 additions and 271 deletions
+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-2026 Andrzej Krzemieński] [copyright 2014-2026 Andrzej Krzemieński]
[category miscellaneous] [category miscellaneous]
[id optional] [id optional]
[dirname optional] [dirname optional]
+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
+2 -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
@@ -138,4 +138,4 @@ The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYP
[caution The support for in-place factories is deprecated. Use constructor taking `in_place_init` tag and function `.emplace()` instead.] [caution The support for in-place factories is deprecated. Use constructor taking `in_place_init` tag and function `.emplace()` instead.]
[endsect] [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`.
+3
View File
@@ -197,6 +197,9 @@ They are empty, trivially copyable classes with disabled default constructor.
template<class F> constexpr 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> constexpr 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__]``
+33 -12
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
@@ -25,31 +26,31 @@ __SPACE__
[: `constexpr 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;`] [: `constexpr optional<T>::optional( none_t ) noexcept;`]
* [*Effect:] Constructs an `optional` uninitialized. * [*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. The expression
* [*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__
@@ -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.
@@ -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].
@@ -752,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 ;`]
@@ -956,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]
+45 -4
View File
@@ -13,13 +13,55 @@
[section Minimum System Requirements] [section Minimum System Requirements]
This library requires C++11 as minimum. However some features are disabled. This library requires C++11 as minimum. However, in C++11 some features are disabled.
For C++14 and higher this library provides a `constexpr` interface for non-mutable [section:constexpr Support for `constexpr`]
member functions and some mutable member functions.
[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->`, [note For types that overload unary `operator&` (address) some member functions in `optional`, like `operator->`,
cannot be implemented as `constexpr` on some compilers.] 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] [endsect]
@@ -30,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]
+47
View File
@@ -11,9 +11,56 @@
[section:relnotes Release Notes] [section:relnotes Release Notes]
[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]
+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
@@ -22,14 +22,22 @@
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/core/addressof.hpp> #include <boost/core/addressof.hpp>
#include <type_traits> #include <type_traits>
#include <boost/optional/detail/optional_factory_support.hpp>
#ifndef BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#include <boost/type_traits/decay.hpp> #include <boost/type_traits/decay.hpp>
#include <boost/type_traits/is_base_of.hpp> #include <boost/type_traits/is_base_of.hpp>
#endif #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
#ifndef BOOST_NO_CXX14_CONSTEXPR #ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
# define BOOST_OPTIONAL_DECAY(T) typename ::std::decay<T>::type # 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)> # define BOOST_OPTIONAL_IS_TAGGED(TAG, U) ::std::is_base_of<TAG, BOOST_OPTIONAL_DECAY(U)>
#else #else
@@ -13,13 +13,13 @@
#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_CONSTEXPR_IMPLEMENTATION #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 #endif
#ifdef BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
# define BOOST_OPTIONAL_TT_PREFIX ::std # define BOOST_OPTIONAL_TT_PREFIX ::std
#else #else
# define BOOST_OPTIONAL_TT_PREFIX boost # define BOOST_OPTIONAL_TT_PREFIX boost
@@ -135,27 +135,27 @@ public:
typedef T* pointer_type; typedef T* pointer_type;
typedef T* pointer_const_type; typedef T* pointer_const_type;
BOOST_CXX14_CONSTEXPR optional() BOOST_NOEXCEPT : ptr_() {} BOOST_CONSTEXPR optional() BOOST_NOEXCEPT : ptr_() {}
BOOST_CXX14_CONSTEXPR optional(none_t) BOOST_NOEXCEPT : ptr_() {} BOOST_CONSTEXPR optional(none_t) BOOST_NOEXCEPT : ptr_() {}
template <class U> template <class U>
BOOST_CXX14_CONSTEXPR 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()) {}
BOOST_CXX14_CONSTEXPR 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, template <class U,
BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>), BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>),
BOOST_OPTIONAL_REQUIRES(detail::is_const_integral_bad_for_conversion<U>)> BOOST_OPTIONAL_REQUIRES(detail::is_const_integral_bad_for_conversion<U>)>
BOOST_CXX14_CONSTEXPR explicit BOOST_CONSTEXPR explicit
optional(U& rhs) BOOST_NOEXCEPT optional(U& rhs) BOOST_NOEXCEPT
: ptr_(boost::addressof(rhs)) {} : ptr_(boost::addressof(rhs)) {}
template <class U, template <class U,
BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>), BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>),
BOOST_OPTIONAL_REQUIRES(!detail::is_const_integral_bad_for_conversion<U>)> BOOST_OPTIONAL_REQUIRES(!detail::is_const_integral_bad_for_conversion<U>)>
BOOST_CXX14_CONSTEXPR BOOST_CONSTEXPR
optional(U& rhs) BOOST_NOEXCEPT optional(U& rhs) BOOST_NOEXCEPT
: ptr_(boost::addressof(rhs)) {} : ptr_(boost::addressof(rhs)) {}
BOOST_CXX14_CONSTEXPR optional& operator=(const optional& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; } BOOST_CXX14_CONSTEXPR optional& operator=(const optional& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
template <class U> template <class U>
@@ -164,50 +164,47 @@ public:
BOOST_CXX14_CONSTEXPR 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_); }
BOOST_CXX14_CONSTEXPR T& get() const { BOOST_ASSERT(ptr_); return *ptr_; } constexpr T& get() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, *ptr_); }
BOOST_CXX14_CONSTEXPR T* get_ptr() const BOOST_NOEXCEPT { return ptr_; } constexpr T* get_ptr() const BOOST_NOEXCEPT { return ptr_; }
BOOST_CXX14_CONSTEXPR T* operator->() const { BOOST_ASSERT(ptr_); return ptr_; } constexpr T* operator->() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, ptr_); }
BOOST_CXX14_CONSTEXPR T& operator*() const { BOOST_ASSERT(ptr_); return *ptr_; } constexpr T& operator*() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, *ptr_); }
BOOST_CXX14_CONSTEXPR 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());
boost::throw_exception(boost::bad_optional_access());
} }
BOOST_CXX14_CONSTEXPR explicit operator bool() const BOOST_NOEXCEPT { return ptr_ != 0; } constexpr explicit operator bool() const BOOST_NOEXCEPT { return ptr_ != 0; }
BOOST_CXX14_CONSTEXPR void reset() BOOST_NOEXCEPT { ptr_ = 0; } BOOST_CXX14_CONSTEXPR void reset() BOOST_NOEXCEPT { ptr_ = 0; }
BOOST_CXX14_CONSTEXPR bool is_initialized() const BOOST_NOEXCEPT { return ptr_ != 0; } constexpr bool is_initialized() const BOOST_NOEXCEPT { return ptr_ != 0; }
BOOST_CXX14_CONSTEXPR 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>
BOOST_CXX14_CONSTEXPR 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>
BOOST_CXX14_CONSTEXPR 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
BOOST_CXX14_CONSTEXPR optional(T&& /* rhs */) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<T&&>(); } optional(T&& /* rhs */) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<T&&>(); }
template <class R, BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, R>)> template <class R, BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, R>)>
BOOST_CXX14_CONSTEXPR optional(R&& r) BOOST_NOEXCEPT BOOST_CXX14_CONSTEXPR optional(R&& r) BOOST_NOEXCEPT
@@ -25,32 +25,32 @@ namespace boost {
// //
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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,32 +128,32 @@ bool operator >= ( T const& x, optional<T> const& y )
// //
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR inline BOOST_CONSTEXPR
bool operator < ( optional<T> const&, none_t ) BOOST_NOEXCEPT bool operator < ( optional<T> const&, none_t ) BOOST_NOEXCEPT
{ return false; } { return false; }
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR inline BOOST_CONSTEXPR
bool operator > ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT bool operator > ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
{ return y < x ; } { return y < x ; }
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR inline BOOST_CONSTEXPR
bool operator <= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT bool operator <= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
{ return !( y < x ) ; } { return !( y < x ) ; }
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR inline BOOST_CONSTEXPR
bool operator >= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT bool operator >= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
{ return !( x < y ) ; } { return !( x < y ) ; }
@@ -162,32 +162,32 @@ bool operator >= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
// //
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR inline BOOST_CONSTEXPR
bool operator > ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT bool operator > ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
{ return y < x ; } { return y < x ; }
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR inline BOOST_CONSTEXPR
bool operator <= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT bool operator <= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
{ return !( y < x ) ; } { return !( y < x ) ; }
template<class T> template<class T>
inline BOOST_CXX14_CONSTEXPR inline BOOST_CONSTEXPR
bool operator >= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT bool operator >= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
{ return !( x < y ) ; } { return !( x < y ) ; }
@@ -0,0 +1,36 @@
// 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)
# 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
@@ -13,13 +13,12 @@
// This header provides definitions required by any specialization of // This header provides definitions required by any specialization of
// optional<>. // optional<>.
#ifndef BOOST_OPTIONAL_DETAIL_CONSTEXPR_OPTIONAL_01FEB2026_HPP #ifndef BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
#define BOOST_OPTIONAL_DETAIL_CONSTEXPR_OPTIONAL_01FEB2026_HPP #define BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
#include <initializer_list> //#include <initializer_list>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/core/invoke_swap.hpp> #include <boost/core/invoke_swap.hpp>
#include <boost/core/invoke_swap.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <boost/optional/bad_optional_access.hpp> #include <boost/optional/bad_optional_access.hpp>
@@ -30,12 +29,20 @@
# define BOOST_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false # define BOOST_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false
// In C++20 we have `std::construct_at()` which is a constexpr equivalent of # ifdef __cpp_guaranteed_copy_elision
// placement-new. We can then make more functions constexpr. # if __cpp_guaranteed_copy_elision
// TBD: This additional constexpr-ication is left for the future. # define BOOST_OPTIONAL_CONSTEXPR_COPY
# define BOOST_OPTIONAL_CXX20_CONSTEXPR # 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 // Missing C++17 type traits
namespace boost { namespace optional_detail { namespace boost { namespace optional_detail {
@@ -47,7 +54,7 @@ struct conjunction<B1> : B1 {};
template <class B1, class... Bn> template <class B1, class... Bn>
struct conjunction<B1, Bn...> struct conjunction<B1, Bn...>
: ::std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {}; : ::std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
}} }}
@@ -67,9 +74,20 @@ union constexpr_union_storage_t
constexpr constexpr_union_storage_t( trivial_init_t ) noexcept : dummy_() {}; 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> template <class... Args>
constexpr constexpr_union_storage_t( Args&&... args ) : value_(forward_<Args>(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 //~constexpr_union_storage_t() = default; // No need to destroy a trivially-destructible type
}; };
@@ -81,9 +99,20 @@ union fallback_union_storage_t
constexpr fallback_union_storage_t( trivial_init_t ) noexcept : dummy_() {}; 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> template <class... Args>
constexpr fallback_union_storage_t( Args&&... args ) : value_(forward_<Args>(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. ~fallback_union_storage_t(){} // My owner will destroy the `T` if needed.
// Cannot default in a union with nontrivial `T`. // Cannot default in a union with nontrivial `T`.
}; };
@@ -108,13 +137,22 @@ struct constexpr_guarded_storage
template <class... Args> explicit constexpr constexpr_guarded_storage(optional_ns::in_place_init_t, Args&&... args) template <class... Args> explicit constexpr constexpr_guarded_storage(optional_ns::in_place_init_t, Args&&... args)
: init_(true), storage_(forward_<Args>(args)...) {} : init_(true), storage_(forward_<Args>(args)...) {}
template <class U, class... Args, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)> // 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) // 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)...) {} // : init_(true), storage_(il, forward_<Args>(args)...) {}
constexpr void reset () noexcept { init_ = false; } BOOST_CXX14_CONSTEXPR void reset () noexcept { init_ = false; }
~constexpr_guarded_storage() = default; //~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
}; };
@@ -130,12 +168,12 @@ struct fallback_guarded_storage
explicit constexpr fallback_guarded_storage(T&& v) : init_(true), storage_(move_(v)) {} explicit constexpr fallback_guarded_storage(T&& v) : init_(true), storage_(move_(v)) {}
template <class... Args> explicit fallback_guarded_storage(optional_ns::in_place_init_t, Args&&... args) template <class... Args> explicit constexpr fallback_guarded_storage(optional_ns::in_place_init_t, Args&&... args)
: init_(true), storage_(forward_<Args>(args)...) {} : init_(true), storage_(forward_<Args>(args)...) {}
template <class U, class... Args, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)> // 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) // explicit fallback_guarded_storage(optional_ns::in_place_init_t, ::std::initializer_list<U> il, Args&&... args)
: init_(true), storage_(il, forward_<Args>(args)...) {} // : init_(true), storage_(il, forward_<Args>(args)...) {}
void reset() noexcept void reset() noexcept
{ {
@@ -148,6 +186,15 @@ struct fallback_guarded_storage
} }
~fallback_guarded_storage() { if (init_) storage_.value_.T::~T(); } ~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
}; };
@@ -169,16 +216,16 @@ namespace boost {
{ {
using storage_t = optional_detail::guarded_storage<T>; using storage_t = optional_detail::guarded_storage<T>;
storage_t storage; storage_t storage;
static_assert( !::std::is_same<typename std::decay<T>::type, none_t>::value, "bad T" ); 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, "bad T" ); 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 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* dataptr() const { return ::boost::addressof(storage.storage_.value_); }
constexpr const T& contained_val() const& { return storage.storage_.value_; } constexpr const T& contained_val() const& { return storage.storage_.value_; }
constexpr T&& contained_val() && { return optional_detail::move_(storage.storage_.value_); } BOOST_CXX14_CONSTEXPR T&& contained_val() && { return optional_detail::move_(storage.storage_.value_); }
constexpr T& contained_val() & { return storage.storage_.value_; } BOOST_CXX14_CONSTEXPR T& contained_val() & { return storage.storage_.value_; }
template <typename... Args> template <typename... Args>
BOOST_OPTIONAL_CXX20_CONSTEXPR void initialize(Args&&... args) BOOST_OPTIONAL_CXX20_CONSTEXPR void initialize(Args&&... args)
@@ -188,6 +235,31 @@ namespace boost {
storage.init_ = true; 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: public:
using value_type = T; using value_type = T;
using unqualified_value_type = typename ::std::remove_const<T>::type; using unqualified_value_type = typename ::std::remove_const<T>::type;
@@ -209,36 +281,97 @@ namespace boost {
constexpr optional(const T& v) : storage(v) {} constexpr optional(const T& v) : storage(v) {}
constexpr optional(T&& v) : storage(optional_detail::move_(v)) {} constexpr optional(T&& v) : storage(optional_detail::move_(v)) {}
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
constexpr optional(bool cond, const T& v) constexpr optional(bool cond, const T& v)
: storage(cond ? storage_t(v) : storage_t()) : storage(conditional_storage_from_values(cond, v))
{} {}
constexpr optional(bool cond, T&& v) constexpr optional(bool cond, T&& v)
: storage(cond ? storage_t(optional_detail::move_(v)) : storage_t()) : storage(conditional_storage_from_values(cond, optional_detail::move_(v)))
{} {}
constexpr optional(const optional& rhs) constexpr optional(const optional& rhs)
: storage(rhs.is_initialized() ? storage_t(*rhs) : storage_t()) : storage(conditional_storage_from_optional(rhs))
{} {}
constexpr optional(optional&& rhs) constexpr optional(optional&& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value) noexcept(::std::is_nothrow_move_constructible<T>::value)
: storage(rhs.is_initialized() ? storage_t(*optional_detail::move_(rhs)) : storage_t()) : storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
{} {}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)> template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)>
constexpr explicit optional(optional<U> const& rhs) constexpr explicit optional(optional<U> const& rhs)
: storage(rhs.is_initialized() ? storage_t(*rhs) : storage_t()) : storage(conditional_storage_from_optional(rhs))
{} {}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)> template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
constexpr explicit optional(optional<U> && rhs) constexpr explicit optional(optional<U> && rhs)
: storage(rhs.is_initialized() ? storage_t(*optional_detail::move_(rhs)) : storage_t()) : 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, template <typename FT,
BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<FT>)> BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<FT>)>
constexpr explicit optional (FT&& factory) /*non-constexpr (deprecated)*/
explicit optional (FT&& factory)
: storage() : storage()
{ {
factory.apply(this->dataptr()); factory.apply(this->dataptr());
@@ -247,15 +380,18 @@ namespace boost {
template <typename FT, template <typename FT,
BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<FT>)> BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<FT>)>
constexpr explicit optional (FT&& factory) /*non-constexpr (deprecated)*/
explicit optional (FT&& factory)
: storage() : storage()
{ {
factory.template apply<T>(this->dataptr()); boost_optional_detail::construct<value_type>(factory, this->dataptr());
storage.init_ = true; storage.init_ = true;
} }
template <typename U, template <typename U,
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, 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>)>
constexpr explicit optional(U&& v) constexpr explicit optional(U&& v)
: storage(optional_ns::in_place_init, optional_detail::forward_<U>(v)) : storage(optional_ns::in_place_init, optional_detail::forward_<U>(v))
{} {}
@@ -265,12 +401,21 @@ namespace boost {
: storage(in_place_init, optional_detail::forward_<Args>(args)...) : storage(in_place_init, optional_detail::forward_<Args>(args)...)
{} {}
template <typename... Args> BOOST_CXX14_CONSTEXPR operator optional<T&>() & noexcept
constexpr explicit optional( in_place_init_if_t, bool cond, Args&&... args ) {
: storage( cond ? storage_t(in_place_init, optional_detail::forward_<Args>(args)...) : storage_t() ) return this->has_value() ? optional<T&>(**this) : optional<T&>();
{} }
constexpr void reset() noexcept 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(); storage.reset();
} }
@@ -283,13 +428,13 @@ namespace boost {
template <typename... Args> template <typename... Args>
BOOST_OPTIONAL_CXX20_CONSTEXPR void emplace(Args&&... args) BOOST_OPTIONAL_CXX20_CONSTEXPR void emplace(Args&&... args)
{ {
reset(); static_assert(noexcept(reset())); reset();
// <-- now we are not containing a value // <-- now we are not containing a value
initialize(optional_detail::forward_<Args>(args)...); initialize(optional_detail::forward_<Args>(args)...);
} }
constexpr optional& operator=(none_t) noexcept BOOST_CXX14_CONSTEXPR optional& operator=(none_t) noexcept
{ {
reset(); reset();
return *this; return *this;
@@ -374,7 +519,9 @@ namespace boost {
BOOST_OPTIONAL_REQUIRES(!::std::is_same<typename ::std::decay<U>::type, optional>), 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(!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_constructible<T, U>),
BOOST_OPTIONAL_REQUIRES(::std::is_assignable<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) BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(U&& v)
{ {
@@ -386,15 +533,17 @@ namespace boost {
} }
template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<F>)> template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<F>)>
/*non-constexpr (deprecated)*/
optional& operator=(F&& factory) optional& operator=(F&& factory)
{ {
reset(); reset();
factory.template apply<T>(this->dataptr()); boost_optional_detail::construct<value_type>(factory, this->dataptr());
storage.init_ = true; storage.init_ = true;
return *this; return *this;
} }
template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<F>)> template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<F>)>
/*non-constexpr (deprecated)*/
optional& operator=(F&& factory) optional& operator=(F&& factory)
{ {
reset(); reset();
@@ -406,7 +555,6 @@ namespace boost {
BOOST_OPTIONAL_CXX20_CONSTEXPR BOOST_OPTIONAL_CXX20_CONSTEXPR
void swap(optional& rhs) void swap(optional& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*rhs, *rhs))) noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*rhs, *rhs)))
// I am cheating here. I need "swapabe" not "assignnable" trait. But this is best I can do in C++14
{ {
if (is_initialized()) if (is_initialized())
{ {
@@ -428,8 +576,8 @@ namespace boost {
constexpr bool has_value() const noexcept { return this->is_initialized(); } constexpr bool has_value() const noexcept { return this->is_initialized(); }
constexpr explicit operator bool() const noexcept { return this->is_initialized(); } constexpr explicit operator bool() const noexcept { return this->is_initialized(); }
constexpr reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->contained_val(); } constexpr reference_const_type get() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(this->is_initialized(), this->contained_val()); }
constexpr reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return 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") //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; } reference_const_type get_value_or (reference_const_type v) const { return this->is_initialized() ? this->contained_val() : v; }
@@ -440,22 +588,19 @@ namespace boost {
pointer_const_type get_ptr() const { return is_initialized() ? dataptr() : nullptr; } pointer_const_type get_ptr() const { return is_initialized() ? dataptr() : nullptr; }
pointer_type get_ptr() { return is_initialized() ? dataptr() : nullptr; } pointer_type get_ptr() { return is_initialized() ? dataptr() : nullptr; }
constexpr reference_const_type operator*() const& { return this->get(); } constexpr reference_const_type operator*() const& { return this->get(); }
constexpr reference_type operator*() & { return this->get(); } BOOST_CXX14_CONSTEXPR reference_type operator*() & { return this->get(); }
constexpr reference_type_of_temporary_wrapper operator*() && { return optional_detail::move_(this->get()); } BOOST_CXX14_CONSTEXPR reference_type_of_temporary_wrapper operator*() && { return optional_detail::move_(this->get()); }
constexpr pointer_const_type operator->() const { BOOST_ASSERT(this->is_initialized()) ; return this->dataptr(); } constexpr pointer_const_type operator->() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(this->is_initialized(), this->dataptr()); }
constexpr pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->dataptr(); } BOOST_CXX14_CONSTEXPR pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->dataptr(); }
constexpr reference_const_type value() const& constexpr reference_const_type value() const&
{ {
if (this->is_initialized()) return this->is_initialized() ? this->get() : (boost::throw_exception(boost::bad_optional_access()), this->get());
return this->get();
else
boost::throw_exception(boost::bad_optional_access());
} }
constexpr reference_type value() & BOOST_CXX14_CONSTEXPR reference_type value() &
{ {
if (this->is_initialized()) if (this->is_initialized())
return this->get(); return this->get();
@@ -463,7 +608,7 @@ namespace boost {
boost::throw_exception(boost::bad_optional_access()); boost::throw_exception(boost::bad_optional_access());
} }
constexpr reference_type_of_temporary_wrapper value() && BOOST_CXX14_CONSTEXPR 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());
@@ -471,17 +616,15 @@ namespace boost {
boost::throw_exception(boost::bad_optional_access()); boost::throw_exception(boost::bad_optional_access());
} }
template <class U = T> 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& constexpr value_type value_or(U&& v) const&
{ {
if (this->is_initialized()) return this->is_initialized() ? get() : T(optional_detail::forward_<U>(v));
return get();
else
return optional_detail::forward_<U>(v);
} }
template <class U> template <class U = typename ::std::remove_cv<T>::type>
constexpr value_type value_or(U&& v) && BOOST_CXX14_CONSTEXPR value_type value_or(U&& v) &&
{ {
if (this->is_initialized()) if (this->is_initialized())
return optional_detail::move_(get()); return optional_detail::move_(get());
@@ -489,17 +632,15 @@ namespace boost {
return optional_detail::forward_<U>(v); return optional_detail::forward_<U>(v);
} }
template <typename F> 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& constexpr value_type value_or_eval(F f) const&
{ {
if (this->is_initialized()) return this->is_initialized() ? get() : value_type(f());
return get();
else
return f();
} }
template <typename F> template <typename F>
constexpr value_type value_or_eval ( F f ) && BOOST_CXX14_CONSTEXPR 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());
@@ -508,7 +649,8 @@ namespace boost {
} }
template <typename F> template <typename F>
constexpr optional<typename optional_detail::result_of<F, reference_type>::type> map(F f) & BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_of<F, reference_type>::type>
map(F f) &
{ {
if (this->has_value()) if (this->has_value())
return f(get()); return f(get());
@@ -517,16 +659,17 @@ namespace boost {
} }
template <typename F> template <typename F>
constexpr optional<typename optional_detail::result_of<F, reference_const_type>::type> map(F f) const& constexpr optional<typename optional_detail::result_of<F, reference_const_type>::type>
map(F f) const&
{ {
if (this->has_value()) return this->has_value() ?
return f(get()); f(get()) :
else optional<typename optional_detail::result_of<F, reference_const_type>::type>();
return none;
} }
template <typename F> template <typename F>
constexpr optional<typename optional_detail::result_of<F, reference_type_of_temporary_wrapper>::type> map(F f) && BOOST_CXX14_CONSTEXPR 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()));
@@ -535,7 +678,7 @@ namespace boost {
} }
template <typename F> template <typename F>
constexpr optional<typename optional_detail::result_value_type<F, reference_type>::type> BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_value_type<F, reference_type>::type>
flat_map(F f) & flat_map(F f) &
{ {
if (this->has_value()) if (this->has_value())
@@ -548,14 +691,13 @@ namespace boost {
constexpr 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;
} }
template <typename F> template <typename F>
constexpr optional<typename optional_detail::result_value_type<F, reference_type_of_temporary_wrapper>::type> BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_value_type<F, reference_type_of_temporary_wrapper>::type>
flat_map(F f) && flat_map(F f) &&
{ {
if (this->has_value()) if (this->has_value())
@@ -577,6 +719,4 @@ namespace boost {
} }
// https://godbolt.org/z/ov1ahMsv6 #endif // BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
#endif // BOOST_OPTIONAL_DETAIL_CONSTEXPR_OPTIONAL_01FEB2026_HPP
+3 -13
View File
@@ -23,15 +23,7 @@
#define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#if !defined(BOOST_NO_CXX14_CONSTEXPR) && \ #include <boost/optional/detail/optional_select_implementation.hpp>
!defined(BOOST_NO_CXX11_REF_QUALIFIERS) && \
!defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
!defined(BOOST_NO_CXX11_UNRESTRICTED_UNION)
# ifdef BOOST_OPTIONAL_CONFIG_ENABLE_CONSTEXPR_IMPLEMENTATION // for now, only per manual request
# define BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION
# endif
#endif
#include <boost/optional/detail/optional_common_defs.hpp> #include <boost/optional/detail/optional_common_defs.hpp>
@@ -56,8 +48,8 @@ operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optiona
#include <boost/none.hpp> #include <boost/none.hpp>
#if defined BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #if defined BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#include <boost/optional/detail/constexpr_optional.hpp> #include <boost/optional/detail/union_optional.hpp>
#else #else
@@ -92,10 +84,8 @@ operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optiona
#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/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>
+13 -6
View File
@@ -17,25 +17,32 @@
#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
#ifdef BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
template<class T> BOOST_OPTIONAL_CXX20_CONSTEXPR void swap ( optional<T>& , optional<T>& ) ; 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 #else
template<class T> void swap ( optional<T>& , optional<T>& ) ; template<class T> void swap ( optional<T>& , optional<T>& ) ;
#endif // BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #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> BOOST_CXX14_CONSTEXPR void swap ( optional<T&>& , optional<T&>& ) BOOST_NOEXCEPT; template<class T> BOOST_CXX14_CONSTEXPR void swap ( optional<T&>& , optional<T&>& ) BOOST_NOEXCEPT;
#endif #endif
+3 -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
] ]
; ;
@@ -39,6 +38,7 @@ run optional_test_assign.cpp ;
run optional_test_swap.cpp ; run optional_test_swap.cpp ;
compile optional_test_constexpr.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_convert_from_T.cpp ; run optional_test_convert_from_T.cpp ;
run optional_test_convert_assign.cpp ; run optional_test_convert_assign.cpp ;
@@ -48,6 +48,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 ;
@@ -79,6 +80,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>());
}
+82 -46
View File
@@ -11,7 +11,7 @@
#include "boost/optional.hpp" #include "boost/optional.hpp"
#ifdef BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
struct Record struct Record
{ {
@@ -20,43 +20,55 @@ struct Record
constexpr int operator()() const { return 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 namespace test_int
{ {
constexpr boost::optional<int> oN; constexpr boost::optional<int> oN;
static_assert(!oN); static_assert(!oN, "");
static_assert(oN == boost::none); static_assert(oN == boost::none, "");
static_assert(oN <= boost::none); static_assert(oN <= boost::none, "");
static_assert(!(oN != boost::none)); static_assert(!(oN != boost::none), "");
static_assert(oN == oN); static_assert(oN == oN, "");
static_assert(!oN.has_value()); static_assert(!oN.has_value(), "");
static_assert(oN.value_or({}) == 0); static_assert(oN.value_or({}) == 0, "");
static_assert(oN.value_or(0) == 0); static_assert(oN.value_or(0) == 0, "");
static_assert(oN.value_or_eval(Record(9)) == 9); 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> oNc = oN;
constexpr boost::optional<int> oNd = boost::none; constexpr boost::optional<int> oNd = boost::none;
constexpr boost::optional<int> oNe = {}; constexpr boost::optional<int> oNe = {};
static_assert(oNc == oN); static_assert(oNc == oN, "");
static_assert(oNd == oN); static_assert(oNd == oN, "");
static_assert(oNe == oN); static_assert(oNe == oN, "");
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);
constexpr bool test_reset() { constexpr bool test_reset() {
boost::optional<int> o = 1; boost::optional<int> o = 1;
@@ -66,31 +78,55 @@ namespace test_int
return o == boost::none; return o == boost::none;
} }
static_assert(test_reset()); static_assert(test_reset(), "");
#endif
} }
namespace test_record namespace test_record
{ {
constexpr boost::optional<Record> rN = boost::none; constexpr boost::optional<Record> rN (boost::none);
constexpr boost::optional<Record> r1 = Record(1); constexpr boost::optional<Record> r1 (Record(1));
constexpr boost::optional<Record> r2 (boost::in_place_init, 2); constexpr boost::optional<Record> r2 (boost::in_place_init, 2);
static_assert(!rN); static_assert(!rN, "");
static_assert(rN == boost::none); static_assert(rN == boost::none, "");
static_assert(r1); static_assert(r1, "");
static_assert(r1 != boost::none); static_assert(r1 != boost::none, "");
static_assert(r2); static_assert(r2, "");
static_assert(rN.value_or(Record(9)).i == 9); static_assert(rN.value_or(Record(9)).i == 9, "");
static_assert(r1->i == 1); static_assert(r1->i == 1, "");
static_assert(r2.value().i == 2); 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 namespace test_optional_ref
{ {
constexpr int gi = 9; constexpr int gi = 9;
constexpr boost::optional<const int&> iref = gi; constexpr boost::optional<const int&> iref = gi;
static_assert(iref); static_assert(iref, "");
static_assert(*iref == 9); static_assert(*iref == 9, "");
} }
#endif // BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #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;
} }
+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();
} }
@@ -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
} }
+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();
} }
+3 -3
View File
@@ -20,7 +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_CONSTEXPR_IMPLEMENTATION #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
@@ -136,11 +136,11 @@ void test_trivial_copyability()
} }
#endif #endif
#endif // BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
int main() int main()
{ {
#ifndef BOOST_OPTIONAL_USES_CONSTEXPR_IMPLEMENTATION #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();
+4 -4
View File
@@ -210,7 +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_CONSTEXPR_IMPLEMENTATION #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 {} ;
@@ -219,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_CONSTEXPR_IMPLEMENTATION #endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
// //
// Specialization of boost::swap: // Specialization of boost::swap:
@@ -353,14 +353,14 @@ 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_CONSTEXPR_IMPLEMENTATION #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_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::template_whose_default_ctor_should_be_used<char>) ) ); ( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) );
#endif #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_CONSTEXPR_IMPLEMENTATION #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_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) ) );