Compare commits

..

1 Commits

Author SHA1 Message Date
Andrzej Krzemienski f564e11dea add robust constexpr support 2026-02-08 11:27:30 +01:00
26 changed files with 60 additions and 862 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
[library Boost.Optional
[quickbook 1.7]
[quickbook 1.4]
[authors [Cacciola Carballal, Fernando Luis]]
[copyright 2003-2007 Fernando Luis Cacciola Carballal]
[copyright 2014-2026 Andrzej Krzemieński]
[copyright 2014-2026 Andrzej Krzemieński]
[category miscellaneous]
[id optional]
[dirname optional]
-12
View File
@@ -50,18 +50,6 @@ In the general case, the internal representation is something equivalent to:
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,
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
+1 -3
View File
@@ -27,7 +27,7 @@ rather than the reference itself.
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
bugs. For more details see
[link optional_reference_binding Dependencies and Portability section].
[link boost_optional.dependencies_and_portability.optional_reference_binding Dependencies and Portability section].
]
[heading Rvalue references]
@@ -39,8 +39,6 @@ Rvalue references and lvalue references to const have the ability in C++ to exte
[endsect]
[#optional_ref_rebinding_semantics]
[section Rebinding semantics for assignment of optional references]
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 In-Place Factories][#boost_optional_factories]
[section In-Place Factories]
One of the typical problems with wrappers and containers is that their
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.]
[endsect:in_place_factories]
[endsect]
+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); //
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_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.design.in_place_factories In-Place Factories]:
optional<T> o;
o.emplace("T", "ctor", "params");
+3 -14
View File
@@ -2,7 +2,7 @@
Boost.Optional
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
Copyright (c) 2015 Andrzej Krzemieński
Copyright (c) 2015 Andrzej Krzemienski
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
@@ -15,25 +15,14 @@
```
namespace boost {
class none_t
{
friend constexpr bool operator==(none_t, none_t) = default;
/* see below */
};
class none_t {/* see below */};
inline constexpr none_t none (/* see below */);
} // 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 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`].
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.
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,9 +197,6 @@ 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_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* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]``
+12 -33
View File
@@ -2,7 +2,6 @@
Boost.Optional
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
Copyright (C) 2014 - 2026 Andrzej Krzemieński.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
@@ -26,31 +25,31 @@ __SPACE__
[: `constexpr optional<T>::optional() noexcept;`]
* [*Postconditions:] `*this` does ['not] contain a value (is "uninitialized").
* [*Remarks:] No contained value is initialized. For every object type `T` these constructors are core constant expressions.
* [*Effect:] Default-Constructs an `optional`.
* [*Postconditions:] `*this` is [_uninitialized].
* [*Notes:] T's default constructor [_is not] called.
* [*Example:]
``
optional<T> oN ;
assert ( !oN ) ;
optional<T> def ;
assert ( !def ) ;
``
__SPACE__
[#reference_optional_constructor_none_t]
[: `constexpr optional<T>::optional( none_t ) noexcept;`]
* [*Postconditions:] `*this` does ['not] contain a value (is "uninitialized").
* [*Remarks:] No contained value is initialized. For every object type `T` these constructors are core constant expressions. The expression
* [*Effect:] Constructs an `optional` uninitialized.
* [*Postconditions:] `*this` is [_uninitialized].
* [*Notes:] `T`'s default constructor [_is not] called. The expression
`boost::none` denotes an instance of `boost::none_t` that can be used as
the parameter.
* [*Example:]
``
#include <boost/none.hpp>
optional<T> n(none) ;
assert ( !n ) ;
assert ( n == none ) ;
``
__SPACE__
@@ -282,7 +281,7 @@ factory.
* [*Postconditions: ] `*this` is [_initialized] and its value is ['directly given]
from the factory `f` (i.e., the value [_is not copied]).
* [*Throws:] Whatever the `T` constructor called by the factory throws.
* [*Notes:] See [link boost_optional_factories In-Place Factories]
* [*Notes:] See [link boost_optional.design.in_place_factories In-Place Factories]
* [*Exception Safety:] Exceptions can only be thrown during the call to
the `T` constructor used by the factory; in that case, this constructor has
no effect.
@@ -525,7 +524,7 @@ factory.
* [*Postconditions: ] `*this` is [_initialized] and its value is ['directly given]
from the factory `f` (i.e., the value [_is not copied]).
* [*Throws:] Whatever the `T` constructor called by the factory throws.
* [*Notes:] See [link boost_optional_factories In-Place Factories]
* [*Notes:] See [link boost_optional.design.in_place_factories In-Place Factories]
* [*Exception Safety:] Exceptions can only be thrown during the call to
the `T` constructor used by the factory; in that case, the `optional` object
will be reset to be ['uninitialized].
@@ -753,26 +752,6 @@ __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]
[: `T const& optional<T>::get_value_or( T const& default) const ;`]
@@ -977,7 +956,7 @@ __SPACE__
* [*Postconditions:] `bool(*this) == bool(rhs)`.
* [*Notes:] This behaviour is called ['rebinding semantics]. See [link optional_ref_rebinding_semantics here] for details.
* [*Notes:] This behaviour is called ['rebinding semantics]. See [link boost_optional.design.optional_references.rebinding_semantics_for_assignment_of_optional_references here] for details.
* [*Example:]
``
+1 -1
View File
@@ -11,7 +11,7 @@
[section Header <boost/optional.hpp>]
This is an alias for header [link ref_header_optional_optional_hpp `<boost/optional/optional.hpp>`].
This is an alias for header [link boost_optional.reference.header__boost_optional_optional_hpp_.header_optional_optional `<boost/optional/optional.hpp>`].
[endsect]
+4 -45
View File
@@ -13,55 +13,13 @@
[section Minimum System Requirements]
This library requires C++11 as minimum. However, in C++11 some features are disabled.
This library requires C++11 as minimum. However some features are disabled.
[section:constexpr Support for `constexpr`]
[section C++11]
For compilers fully supporting C++11 (including unconstrained unions and ref-qualifiers),
for trivially-destructible `T`s, `optional<T>` is a ['literal type] and its constructors
with `this->has_value() == false` as postcondition:
* `optional()`,
* `optional(none_t)`,
are ['core constant expressions]. Even for other `T`s, these constructors are guaranteed to
perform ['constant initialization]: they are never subject to "initialization order fiasco".
Other constructors with `this->has_value() == true`
as postcondition are core constant expressions if the expression required to initialize
the contained value is a core constant expression. This includes constructors:
* `template <typename... Args> optional(in_place_init, Args&&...)`,
* `template <typename U> optional(U&&)`,
* `optional(const T&)`,
* `optional(T&&)`.
Other constructors, including the copy and move constructos, are ['not] core constant expressions.
Member functions `.has_value`, `operator bool` and (non)equality comparisons with `none` are core-constant expressions for trivially-destructible `T`s.
Also all `const`-qualified non-static member functions and comparison operators are core constant expressions, if the corresponding operations on `T`
are core constant expressions.
[endsect]
[section C++14]
For C++14 and higher this library, for trivially-destructible `T`s provides the `constexpr` interface for all mutable and non-mutable
member functions, as long as:
* the corresponding operations on `T` are core constant expressions and
* the member never attempts to change the `optional`'s state from not containing a value to containing a value.
For C++14 and higher this library provides a `constexpr` interface for non-mutable
member functions and some mutable member functions.
[note For types that overload unary `operator&` (address) some member functions in `optional`, like `operator->`,
cannot be implemented as `constexpr` on some compilers.]
[endsect]
[section C++17]
In C++17 all non-deprecated constructors are core constant expressions as long as
`T` is a literal type and its constructor used is a core constant expression.
[endsect]
[endsect:constexpr]
[endsect]
@@ -72,6 +30,7 @@ The implementation uses the following other Boost modules:
# assert
# config
# core
# static_assert
# throw_exception
# type_traits
+3 -18
View File
@@ -11,7 +11,8 @@
[section:std_comp Comparison with `std::optional`]
[table Comparison with `std::optional`
[table
[]
[ [[*`boost::optional`]] [[*`std::optional`]] [] ]
[ [`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.] ]
@@ -41,23 +42,7 @@
[ [`make_optional(cond, v);`] [] [No `make_optional` with condition in `std`.] ]
[ [] [`make_optional<T>(a, b);`] [No `make_optional` with specified `T` in `boost`.] ]
[ [`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]
-51
View File
@@ -11,60 +11,9 @@
[section:relnotes Release Notes]
[heading Boost Release 1.xx]
* Fixed regression in the copy-initialization of `optional<bool>`. This fixes [@https://github.com/boostorg/optional/issues/146 issue #146].
[heading Boost Release 1.91]
* For compilers with full C++11 support (including "unrestricted unions" and ref-qualifiers)
changed the implementation from aligned storage to union storage. This enables the gradual
`constexpr` support:
* In C++11, some constructors and `const`-qualified accessors become usable
in compile-time contexts (are ['core constant expressions]) for types
satisfying certain constraints.
* In C++14 even some mutating operations become core constant expressions (those
that do not require changing the state of `optional` from not having a value to
having a value), for co-operating types.
* In C++17 all constructors (including copy and move) become core constant expressions
for co-operating types.
This addresses issues [@https://github.com/boostorg/optional/issues/132 #132] and [@https://github.com/boostorg/optional/issues/143 #143].
* *Breaking change.* In the said implementation, abandoned the mechanism for customizing
`swap`. Hardly anyone knows about this mechanism and it was never documented.
* In the said implementation, applied a couple of small changes to get closer to the interface of `std::optional`:
* Enabled syntax `o = {}` for putting optional objects to no-value state.
* Enabled syntax `o.value_or({})`, which uses a default-constructed `T`.
* Construct `o = u`, where `o` is of type `optional<T>` and `u` is of type `U` convertible to `T`,
does not create a temporary `T`.
* In the said implementation, added a conversion from `optional<T>&` to `optional<T&>`. This addresses [@https://github.com/boostorg/optional/issues/142 issue #142].
* `none_t` is now `std::equality_comparable`, which means that `none_t` and `optional<T>`
model concept `std::equality_comparable_with` (for `std::equality_comparable` `T`s),
which means that you can `std::ranges::find(rng, boost::none)` for a range of optional objects.
* *Warning.* In the future releases we intend to introduce the range interface
in `optional`, so that `std::ranges::range<optional<T>>` will be `true`.
This may affect the overload resolution in programs that make decisions based
on predicates such as `std::ranges::range`. For instance, the following code
will start behaving differently:
```
template <typename T>
void serialize(T const& v)
{
if constexpr (std::ranges::range<T>)
serialize_as_range(v);
else if constexpr (custom::is_optional_like<T>)
serialize_as_optional(v);
else
serialize_as_value(v);
}
```
[heading Boost Release 1.87]
+1 -6
View File
@@ -25,7 +25,7 @@
#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.92.")
BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Optional 1.83 and will be removed in Boost.Optional 1.88.")
#endif
@@ -46,11 +46,6 @@ struct none_t
{
struct init_tag{};
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
@@ -22,7 +22,6 @@
#include <boost/config.hpp>
#include <boost/core/addressof.hpp>
#include <type_traits>
#include <boost/optional/detail/optional_factory_support.hpp>
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#include <boost/type_traits/decay.hpp>
@@ -23,8 +23,7 @@
!defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
!defined(BOOST_NO_CXX11_UNRESTRICTED_UNION) && \
!defined(BOOST_NO_CXX11_NOEXCEPT) && \
!defined(BOOST_NO_CXX11_DEFAULTED_MOVES) && \
!defined(BOOST_OPTIONAL_CONFIG_DISABLE_UNION_OPTIONAL)
!defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
# define BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#endif
@@ -74,20 +74,9 @@ union constexpr_union_storage_t
constexpr constexpr_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
// false positive, see https://github.com/boostorg/variant2/issues/55,
// https://github.com/boostorg/url/issues/979
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <class... Args>
constexpr constexpr_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
# pragma GCC diagnostic pop
#endif
//~constexpr_union_storage_t() = default; // No need to destroy a trivially-destructible type
};
@@ -99,20 +88,9 @@ union fallback_union_storage_t
constexpr fallback_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
// false positive, see https://github.com/boostorg/variant2/issues/55,
// https://github.com/boostorg/url/issues/979
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <class... Args>
constexpr fallback_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
# pragma GCC diagnostic pop
#endif
~fallback_union_storage_t(){} // My owner will destroy the `T` if needed.
// Cannot default in a union with nontrivial `T`.
};
@@ -144,15 +122,6 @@ struct constexpr_guarded_storage
BOOST_CXX14_CONSTEXPR void reset () noexcept { init_ = false; }
//~constexpr_guarded_storage() = default;
#if (defined(_MSC_VER) && 1910 <= _MSC_VER && _MSC_VER <= 1916)
// Workaround for MSVC 14.1x bug where it eagerly tries to define the copy/move operations
// these are declared but never defined
constexpr_guarded_storage(const constexpr_guarded_storage&);
constexpr_guarded_storage(constexpr_guarded_storage&&);
constexpr_guarded_storage& operator=(const constexpr_guarded_storage&);
constexpr_guarded_storage& operator=(constexpr_guarded_storage&&);
#endif
};
@@ -186,15 +155,6 @@ struct fallback_guarded_storage
}
~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
};
@@ -235,31 +195,6 @@ namespace boost {
storage.init_ = true;
}
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
// The conditional initialization of storage needs to employ a factory
// function, so that we can utilize the guaranteed copy elision on the
// return type.
// an alternative -- using a conditional operator in the initializer --
// does not work in MSVC 14.2 and 14.3.
template <typename... U>
static constexpr storage_t conditional_storage_from_values(bool cond, U&&... v)
{
if (cond)
return storage_t(in_place_init, optional_detail::forward_<U>(v)...);
else
return storage_t();
}
template <typename OU>
static constexpr storage_t conditional_storage_from_optional(OU&& ou)
{
if (ou.has_value())
return storage_t(in_place_init, *optional_detail::forward_<OU>(ou));
else
return storage_t();
}
#endif
public:
using value_type = T;
using unqualified_value_type = typename ::std::remove_const<T>::type;
@@ -283,35 +218,35 @@ namespace boost {
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
constexpr optional(bool cond, const T& v)
: storage(conditional_storage_from_values(cond, v))
: storage(cond ? storage_t(v) : storage_t())
{}
constexpr optional(bool cond, T&& v)
: storage(conditional_storage_from_values(cond, optional_detail::move_(v)))
: storage(cond ? storage_t(optional_detail::move_(v)) : storage_t())
{}
constexpr optional(const optional& rhs)
: storage(conditional_storage_from_optional(rhs))
: storage(rhs.is_initialized() ? storage_t(*rhs) : storage_t())
{}
constexpr optional(optional&& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value)
: storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
: storage(rhs.is_initialized() ? storage_t(*optional_detail::move_(rhs)) : storage_t())
{}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)>
constexpr explicit optional(optional<U> const& rhs)
: storage(conditional_storage_from_optional(rhs))
: storage(rhs.is_initialized() ? storage_t(in_place_init, *rhs) : storage_t())
{}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
constexpr explicit optional(optional<U> && rhs)
: storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
: storage(rhs.is_initialized() ? storage_t(in_place_init, *optional_detail::move_(rhs)) : storage_t())
{}
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)...))
: storage( cond ? storage_t(in_place_init, optional_detail::forward_<Args>(args)...) : storage_t() )
{}
#else
optional(bool cond, const T& v)
@@ -384,16 +319,12 @@ namespace boost {
explicit optional (FT&& factory)
: storage()
{
boost_optional_detail::construct<value_type>(factory, this->dataptr());
factory.template apply<T>(this->dataptr());
storage.init_ = true;
}
template <typename U,
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_typed_in_place_factory<U>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_in_place_factory<U>),
BOOST_OPTIONAL_REQUIRES(!BOOST_OPTIONAL_IS_TAGGED(optional_detail::optional_tag, U))
>
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
constexpr explicit optional(U&& v)
: storage(optional_ns::in_place_init, optional_detail::forward_<U>(v))
{}
@@ -403,20 +334,6 @@ namespace boost {
: storage(in_place_init, optional_detail::forward_<Args>(args)...)
{}
BOOST_CXX14_CONSTEXPR operator optional<T&>() & noexcept
{
return this->has_value() ? optional<T&>(**this) : optional<T&>();
}
BOOST_CONSTEXPR operator optional<const T&>() const& noexcept
{
return this->has_value() ? optional<const T&>(**this) : optional<const T&>();
}
BOOST_CXX14_CONSTEXPR operator optional<T&>() && noexcept = delete;
BOOST_CONSTEXPR operator optional<const T&>() const&& noexcept = delete;
BOOST_CXX14_CONSTEXPR void reset() noexcept
{
storage.reset();
@@ -521,9 +438,7 @@ namespace boost {
BOOST_OPTIONAL_REQUIRES(!::std::is_same<typename ::std::decay<U>::type, optional>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::conjunction<::std::is_scalar<T>, ::std::is_same<T, BOOST_OPTIONAL_DECAY(U)>>),
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U>),
BOOST_OPTIONAL_REQUIRES(::std::is_assignable<T&, U>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_typed_in_place_factory<U>),
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_in_place_factory<U>)
BOOST_OPTIONAL_REQUIRES(::std::is_assignable<T&, U>)
>
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(U&& v)
{
@@ -539,7 +454,7 @@ namespace boost {
optional& operator=(F&& factory)
{
reset();
boost_optional_detail::construct<value_type>(factory, this->dataptr());
factory.template apply<T>(this->dataptr());
storage.init_ = true;
return *this;
}
+2
View File
@@ -84,8 +84,10 @@ operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optiona
#include <boost/type_traits/is_volatile.hpp>
#include <boost/type_traits/is_scalar.hpp>
#include <boost/optional/optional_fwd.hpp>
#include <boost/optional/detail/optional_config.hpp>
#include <boost/optional/detail/optional_factory_support.hpp>
#include <boost/optional/detail/optional_aligned_storage.hpp>
+1 -3
View File
@@ -28,6 +28,7 @@ project
cxx11_explicit_conversion_operators
# cxx11_noexcept
cxx11_rvalue_references
cxx11_static_assert
cxx11_variadic_templates
]
;
@@ -40,7 +41,6 @@ compile optional_test_constexpr.cpp ;
compile optional_test_wuninitialized.cpp ;
compile optional_test_fwd_header.cpp ;
run optional_test_conversions_from_U.cpp ;
run optional_test_constructors.cpp ;
run optional_test_convert_from_T.cpp ;
run optional_test_convert_assign.cpp ;
run optional_test_empty_braces.cpp ;
@@ -49,7 +49,6 @@ run optional_test_flat_map.cpp ;
run optional_test_hash.cpp ;
run optional_test_map.cpp ;
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_mutable_int.cpp ;
run optional_test_ref_assign_const_int.cpp ;
@@ -81,7 +80,6 @@ compile-fail optional_test_fail3b.cpp ;
compile-fail optional_test_ref_fail1.cpp ;
compile-fail optional_test_ref_fail3.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_fail2.cpp ;
compile-fail optional_test_fail_implicit_bool_convert.cpp ;
+1 -34
View File
@@ -20,16 +20,6 @@ struct Record
constexpr int operator()() const { return i; }
};
struct Guard
{
int i;
constexpr explicit Guard(int i) : i(i) {}
Guard(Guard&&) = delete;
};
static_assert(boost::none == boost::none, "");
static_assert(!(boost::none != boost::none), "");
namespace test_int
{
constexpr boost::optional<int> oN;
@@ -62,7 +52,7 @@ namespace test_int
static_assert(o2 != o1, "");
static_assert(o2 > o1, "");
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
#ifndef BOOST_NO_CXX14_CONSTEXPR
constexpr boost::optional<int> oNc = oN;
constexpr boost::optional<int> oNd = boost::none;
constexpr boost::optional<int> oNe = {};
@@ -98,29 +88,6 @@ namespace test_record
static_assert(r2.value().i == 2, "");
}
namespace test_guard
{
constexpr boost::optional<Guard> g1 {boost::in_place_init, 1};
constexpr boost::optional<Guard> gNa {boost::none};
constexpr boost::optional<Guard> gNb;
static_assert(g1, "");
static_assert(!!g1, "");
static_assert(g1 != boost::none, "");
static_assert(!(g1 == boost::none), "");
static_assert(g1.has_value(), "");
static_assert(!gNa, "");
static_assert(!gNa.has_value(), "");
static_assert(gNa == boost::none, "");
static_assert(!(gNa != boost::none), "");
static_assert(!gNb, "");
static_assert(!gNb.has_value(), "");
static_assert(gNb == boost::none, "");
static_assert(!(gNb != boost::none), "");
}
namespace test_optional_ref
{
constexpr int gi = 9;
-287
View File
@@ -1,287 +0,0 @@
// Copyright (C) 2026 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
#include "boost/optional/optional.hpp"
#include "boost/core/lightweight_test.hpp"
#include <string>
using boost::optional;
using boost::none;
struct MyBool
{
bool b;
MyBool (bool b) : b(b) {}
operator bool() const { return b; };
};
struct MyExplicitBool
{
bool b;
MyExplicitBool (bool b) : b(b) {}
operator bool() const { return b; };
};
struct Any
{
template <typename... T>
Any(T&&...) {}
};
struct JustCopyMoveCtor
{
JustCopyMoveCtor(JustCopyMoveCtor&&) = default;
JustCopyMoveCtor(JustCopyMoveCtor const&) = default;
JustCopyMoveCtor& operator=(JustCopyMoveCtor&&) = delete;
JustCopyMoveCtor& operator=(JustCopyMoveCtor const&) = delete;
JustCopyMoveCtor() = delete;
};
struct JustDefault
{
JustDefault() = default;
JustDefault(JustDefault&&) = delete;
};
template <typename T>
optional<T> empty_optional()
{
return optional<T>(); // this is to avoid "the most vexing parse"
}
template <typename T, typename U>
void direct_test_ctor_optional_T_from_empty_optional_T()
{
optional<U> om;
const optional<U> oc;
BOOST_TEST(!om);
BOOST_TEST(!oc);
{
optional<T> ox = om;
BOOST_TEST(!ox);
optional<T> oy = oc;
BOOST_TEST(!oy);
optional<T> oz = empty_optional<U>();
BOOST_TEST(!oz);
}
{
optional<T> ox = {om};
BOOST_TEST(!ox);
optional<T> oy = {oc};
BOOST_TEST(!oy);
optional<T> oz = {empty_optional<U>()};
BOOST_TEST(!oz);
}
{
optional<T> ox{om};
BOOST_TEST(!ox);
optional<T> oy{oc};
BOOST_TEST(!oy);
optional<T> oz{empty_optional<U>()};
BOOST_TEST(!oz);
}
{
optional<T> ox(om);
BOOST_TEST(!ox);
optional<T> oy(oc);
BOOST_TEST(!oy);
optional<T> oz(empty_optional<U>());
BOOST_TEST(!oz);
}
}
template <typename T, typename U>
void test_ctor_optional_T_from_empty_optional_T()
{
direct_test_ctor_optional_T_from_empty_optional_T<T, U>();
direct_test_ctor_optional_T_from_empty_optional_T<const T, const U>();
direct_test_ctor_optional_T_from_empty_optional_T<optional<T>, optional<U>>();
direct_test_ctor_optional_T_from_empty_optional_T<optional<const T>, optional<const U>>();
direct_test_ctor_optional_T_from_empty_optional_T<const optional<T>, const optional<U>>();
}
template <typename T, typename U>
void direct_test_ctor_optional_T_from_optional_U(U val)
{
optional<U> om;
const optional<U> oc;
BOOST_TEST(!om);
BOOST_TEST(!oc);
{
optional<T> ox{om};
BOOST_TEST(!ox);
optional<T> oy{oc};
BOOST_TEST(!oy);
optional<T> oz{empty_optional<U>()};
BOOST_TEST(!oz);
}
{
optional<T> ox(om);
BOOST_TEST(!ox);
optional<T> oy(oc);
BOOST_TEST(!oy);
optional<T> oz(empty_optional<U>());
BOOST_TEST(!oz);
}
{
optional<U> om {val};
const optional<U> oc {val};
{
optional<T> ox{om};
BOOST_TEST(ox);
optional<T> oy{oc};
BOOST_TEST(oy);
optional<T> oz{boost::make_optional(val)};
BOOST_TEST(oz);
}
{
optional<T> ox(om);
BOOST_TEST(ox);
optional<T> oy(oc);
BOOST_TEST(oy);
optional<T> oz(boost::make_optional(val));
BOOST_TEST(oz);
}
}
}
template <typename T, typename U>
void test_ctor_optional_T_from_optional_U(U val)
{
direct_test_ctor_optional_T_from_optional_U<T>(val);
}
template <typename T>
void direct_test_ctor_optional_T_from_valued_optional_T(T val)
{
optional<T> om(val);
const optional<T> oc(val);
BOOST_TEST(om);
BOOST_TEST(oc);
{
optional<T> ox = om;
BOOST_TEST(ox);
optional<T> oy = oc;
BOOST_TEST(oy);
optional<T> oz = optional<T>(val);
BOOST_TEST(oz);
}
{
optional<T> ox = {om};
BOOST_TEST(ox);
optional<T> oy = {oc};
BOOST_TEST(oy);
optional<T> oz = {optional<T>(val)};
BOOST_TEST(oz);
}
}
template <typename T>
void test_ctor_optional_T_from_valued_optional_T(T val)
{
direct_test_ctor_optional_T_from_valued_optional_T<T>(val);
direct_test_ctor_optional_T_from_valued_optional_T<optional<T>>(val);
direct_test_ctor_optional_T_from_valued_optional_T<const T>(val);
direct_test_ctor_optional_T_from_optional_U<T, T>(val);
direct_test_ctor_optional_T_from_optional_U<optional<T>, optional<T>>(val);
}
template <typename T>
void direct_test_inplace_tag_constructor()
{
{
optional<T> ox (boost::in_place_init);
BOOST_TEST(ox);
}
{
optional<T> ox {boost::in_place_init};
BOOST_TEST(ox);
}
}
template <typename T>
void test_inplace_tag_constructor()
{
direct_test_inplace_tag_constructor<T>();
direct_test_inplace_tag_constructor<optional<T>>();
}
int main()
{
test_ctor_optional_T_from_empty_optional_T<int, int>();
test_ctor_optional_T_from_empty_optional_T<long, long>();
test_ctor_optional_T_from_empty_optional_T<std::string, std::string>();
test_ctor_optional_T_from_empty_optional_T<JustCopyMoveCtor, JustCopyMoveCtor>();
test_ctor_optional_T_from_empty_optional_T<MyBool, MyBool>();
test_ctor_optional_T_from_empty_optional_T<MyExplicitBool, MyExplicitBool>();
test_ctor_optional_T_from_empty_optional_T<bool, bool>();
test_ctor_optional_T_from_empty_optional_T<Any, Any>();
test_inplace_tag_constructor<int>();
test_inplace_tag_constructor<Any>();
test_inplace_tag_constructor<JustDefault>();
test_ctor_optional_T_from_optional_U<int>(1);
test_ctor_optional_T_from_optional_U<long>(1);
test_ctor_optional_T_from_optional_U<bool>(MyBool{true});
test_ctor_optional_T_from_optional_U<bool>(MyBool{false});
test_ctor_optional_T_from_optional_U<MyBool>(true);
test_ctor_optional_T_from_optional_U<MyBool>(false);
test_ctor_optional_T_from_optional_U<bool>(MyExplicitBool{true});
test_ctor_optional_T_from_optional_U<bool>(MyExplicitBool{false});
test_ctor_optional_T_from_optional_U<MyExplicitBool>(true);
test_ctor_optional_T_from_optional_U<MyExplicitBool>(false);
test_ctor_optional_T_from_optional_U<Any>(true);
test_ctor_optional_T_from_optional_U<Any>(Any{});
test_ctor_optional_T_from_valued_optional_T(1);
optional<MyBool> ob;
optional<bool> oa;
oa = ob;
BOOST_TEST(!oa);
return boost::report_errors();
}
-2
View File
@@ -45,8 +45,6 @@ void test_optional_of_superconverting_T() // compile-time test
superconv<optional<int> > s;
superconv<optional<int> > & rs = s;
optional<superconv<optional<int> > > os = rs;
(void)s;
(void)os;
#endif
}
-33
View File
@@ -105,42 +105,9 @@ void test_assign()
#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()
{
test_ctor();
test_assign();
test_boost_log_case();
return boost::report_errors();
}
@@ -32,7 +32,6 @@ void test()
//BOOST_TEST(v);
boost::optional<boost::optional<int>> vv;
bool xx = vv?true : false;
(void)xx;
BOOST_TEST_EQ(*v, 7);
#endif
}
-70
View File
@@ -1,70 +0,0 @@
// 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();
}
@@ -1,21 +0,0 @@
// 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;
}
+14 -121
View File
@@ -24,13 +24,7 @@ using boost::none;
struct Value
{
int val;
BOOST_CONSTEXPR explicit Value(int v) : val(v) {}
};
struct Guard
{
int val;
BOOST_CONSTEXPR explicit Guard(int v) : val(v) {}
explicit Value(int v) : val(v) {}
};
int val(int const& i)
@@ -43,11 +37,6 @@ int val(Value const& v)
return v.val;
}
int val(Guard const& v)
{
return v.val;
}
template <typename Tref>
optional<Tref&> make_opt_ref(Tref& v)
{
@@ -58,21 +47,21 @@ template <typename Tval, typename Tref>
void test_construct_from_optional_ref()
{
Tref v1 (1), v2 (2);
optional<Tref&> opt_ref0;
optional<Tref&> opt_ref1 (v1);
optional<Tval> opt_val0 (opt_ref0);
optional<Tval> opt_val1 (opt_ref1);
optional<Tval> opt_val2 (make_opt_ref(v2));
BOOST_TEST (!opt_val0);
BOOST_TEST (opt_val1);
BOOST_TEST (opt_val2);
BOOST_TEST_EQ (1, val(*opt_val1));
BOOST_TEST_EQ (2, val(*opt_val2));
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2));
}
@@ -81,121 +70,29 @@ template <typename Tval, typename Tref>
void test_assign_from_optional_ref()
{
Tref v1 (1), v2 (2);
optional<Tref&> opt_ref0;
optional<Tref&> opt_ref1 (v1);
optional<Tval> opt_val0;
optional<Tval> opt_val1;
optional<Tval> opt_val2;
opt_val0 = opt_ref0;
opt_val1 = opt_ref1;
opt_val2 = make_opt_ref(v2);
BOOST_TEST (!opt_val0);
BOOST_TEST (opt_val1);
BOOST_TEST (opt_val2);
BOOST_TEST_EQ (1, val(*opt_val1));
BOOST_TEST_EQ (2, val(*opt_val2));
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
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()
{
@@ -203,21 +100,17 @@ int main()
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>();
test_construct_from_optional_ref<Value, Value>();
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>();
test_assign_from_optional_ref<int, int>();
test_assign_from_optional_ref<int, int const>();
test_assign_from_optional_ref<Value, Value>();
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();
}