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 [library Boost.Optional
[quickbook 1.7] [quickbook 1.4]
[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,18 +50,6 @@ 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
+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, 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 optional_reference_binding Dependencies and Portability section]. [link boost_optional.dependencies_and_portability.optional_reference_binding Dependencies and Portability section].
] ]
[heading Rvalue references] [heading Rvalue references]
@@ -39,8 +39,6 @@ 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 In-Place Factories][#boost_optional_factories] [section In-Place 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: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); // 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_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; optional<T> o;
o.emplace("T", "ctor", "params"); o.emplace("T", "ctor", "params");
+3 -14
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 Krzemieński Copyright (c) 2015 Andrzej Krzemienski
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
@@ -15,25 +15,14 @@
``` ```
namespace boost { namespace boost {
class none_t class none_t {/* see below */};
{
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. 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.
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,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 __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__]``
+12 -33
View File
@@ -2,7 +2,6 @@
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
@@ -26,31 +25,31 @@ __SPACE__
[: `constexpr optional<T>::optional() noexcept;`] [: `constexpr optional<T>::optional() noexcept;`]
* [*Postconditions:] `*this` does ['not] contain a value (is "uninitialized"). * [*Effect:] Default-Constructs an `optional`.
* [*Remarks:] No contained value is initialized. For every object type `T` these constructors are core constant expressions. * [*Postconditions:] `*this` is [_uninitialized].
* [*Notes:] T's default constructor [_is not] called.
* [*Example:] * [*Example:]
`` ``
optional<T> oN ; optional<T> def ;
assert ( !oN ) ; assert ( !def ) ;
`` ``
__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;`]
* [*Postconditions:] `*this` does ['not] contain a value (is "uninitialized"). * [*Effect:] Constructs an `optional` uninitialized.
* [*Remarks:] No contained value is initialized. For every object type `T` these constructors are core constant expressions. The expression * [*Postconditions:] `*this` is [_uninitialized].
* [*Notes:] `T`'s default constructor [_is not] called. The expression
`boost::none` denotes an instance of `boost::none_t` that can be used as `boost::none` denotes an instance of `boost::none_t` that can be used as
the parameter. the parameter.
* [*Example:] * [*Example:]
`` ``
#include <boost/none.hpp> #include <boost/none.hpp>
optional<T> n(none) ; optional<T> n(none) ;
assert ( !n ) ; assert ( !n ) ;
assert ( n == none ) ;
`` ``
__SPACE__ __SPACE__
@@ -282,7 +281,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_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 * [*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.
@@ -525,7 +524,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_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 * [*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].
@@ -753,26 +752,6 @@ __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 ;`]
@@ -977,7 +956,7 @@ __SPACE__
* [*Postconditions:] `bool(*this) == bool(rhs)`. * [*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:] * [*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 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] [endsect]
+4 -45
View File
@@ -13,55 +13,13 @@
[section Minimum System Requirements] [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`] For C++14 and higher this library provides a `constexpr` interface for non-mutable
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]
@@ -72,6 +30,7 @@ The implementation uses the following other Boost modules:
# assert # assert
# config # config
# core # core
# static_assert
# throw_exception # throw_exception
# type_traits # type_traits
+3 -18
View File
@@ -11,7 +11,8 @@
[section:std_comp Comparison with `std::optional`] [section:std_comp Comparison with `std::optional`]
[table Comparison with `std::optional` [table
[]
[ [[*`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.] ]
@@ -41,23 +42,7 @@
[ [`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]
-51
View File
@@ -11,60 +11,9 @@
[section:relnotes Release Notes] [section:relnotes Release Notes]
[heading Boost Release 1.xx]
* Fixed regression in the copy-initialization of `optional<bool>`. This fixes [@https://github.com/boostorg/optional/issues/146 issue #146].
[heading Boost Release 1.91]
* For compilers with full C++11 support (including "unrestricted unions" and ref-qualifiers)
changed the implementation from aligned storage to union storage. This enables the gradual
`constexpr` support:
* In C++11, some constructors and `const`-qualified accessors become usable
in compile-time contexts (are ['core constant expressions]) for types
satisfying certain constraints.
* In C++14 even some mutating operations become core constant expressions (those
that do not require changing the state of `optional` from not having a value to
having a value), for co-operating types.
* In C++17 all constructors (including copy and move) become core constant expressions
for co-operating types.
This addresses issues [@https://github.com/boostorg/optional/issues/132 #132] and [@https://github.com/boostorg/optional/issues/143 #143].
* *Breaking change.* In the said implementation, abandoned the mechanism for customizing
`swap`. Hardly anyone knows about this mechanism and it was never documented.
* In the said implementation, applied a couple of small changes to get closer to the interface of `std::optional`:
* Enabled syntax `o = {}` for putting optional objects to no-value state.
* Enabled syntax `o.value_or({})`, which uses a default-constructed `T`.
* Construct `o = u`, where `o` is of type `optional<T>` and `u` is of type `U` convertible to `T`,
does not create a temporary `T`.
* In the said implementation, added a conversion from `optional<T>&` to `optional<T&>`. This addresses [@https://github.com/boostorg/optional/issues/142 issue #142].
* `none_t` is now `std::equality_comparable`, which means that `none_t` and `optional<T>`
model concept `std::equality_comparable_with` (for `std::equality_comparable` `T`s),
which means that you can `std::ranges::find(rng, boost::none)` for a range of optional objects.
* *Warning.* In the future releases we intend to introduce the range interface
in `optional`, so that `std::ranges::range<optional<T>>` will be `true`.
This may affect the overload resolution in programs that make decisions based
on predicates such as `std::ranges::range`. For instance, the following code
will start behaving differently:
```
template <typename T>
void serialize(T const& v)
{
if constexpr (std::ranges::range<T>)
serialize_as_range(v);
else if constexpr (custom::is_optional_like<T>)
serialize_as_optional(v);
else
serialize_as_value(v);
}
```
[heading Boost Release 1.87] [heading Boost Release 1.87]
+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) #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 #endif
@@ -46,11 +46,6 @@ 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,7 +22,6 @@
#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_UNION_IMPLEMENTATION #ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#include <boost/type_traits/decay.hpp> #include <boost/type_traits/decay.hpp>
@@ -23,8 +23,7 @@
!defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \ !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
!defined(BOOST_NO_CXX11_UNRESTRICTED_UNION) && \ !defined(BOOST_NO_CXX11_UNRESTRICTED_UNION) && \
!defined(BOOST_NO_CXX11_NOEXCEPT) && \ !defined(BOOST_NO_CXX11_NOEXCEPT) && \
!defined(BOOST_NO_CXX11_DEFAULTED_MOVES) && \ !defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
!defined(BOOST_OPTIONAL_CONFIG_DISABLE_UNION_OPTIONAL)
# define BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION # define BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
#endif #endif
@@ -74,20 +74,9 @@ 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
}; };
@@ -99,20 +88,9 @@ 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`.
}; };
@@ -144,15 +122,6 @@ struct constexpr_guarded_storage
BOOST_CXX14_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
}; };
@@ -186,15 +155,6 @@ 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
}; };
@@ -235,31 +195,6 @@ 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;
@@ -283,35 +218,35 @@ namespace boost {
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY #ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
constexpr optional(bool cond, const T& v) 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) 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) constexpr optional(const optional& rhs)
: storage(conditional_storage_from_optional(rhs)) : storage(rhs.is_initialized() ? storage_t(*rhs) : storage_t())
{} {}
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(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&>)> 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(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&&>)> template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
constexpr explicit optional(optional<U> && rhs) 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> template <typename... Args>
constexpr explicit optional( in_place_init_if_t, bool cond, Args&&... 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 #else
optional(bool cond, const T& v) optional(bool cond, const T& v)
@@ -384,16 +319,12 @@ namespace boost {
explicit optional (FT&& factory) explicit optional (FT&& factory)
: storage() : storage()
{ {
boost_optional_detail::construct<value_type>(factory, this->dataptr()); factory.template apply<T>(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>),
BOOST_OPTIONAL_REQUIRES(!BOOST_OPTIONAL_IS_TAGGED(optional_detail::optional_tag, 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))
{} {}
@@ -403,20 +334,6 @@ namespace boost {
: storage(in_place_init, optional_detail::forward_<Args>(args)...) : storage(in_place_init, optional_detail::forward_<Args>(args)...)
{} {}
BOOST_CXX14_CONSTEXPR operator optional<T&>() & noexcept
{
return this->has_value() ? optional<T&>(**this) : optional<T&>();
}
BOOST_CONSTEXPR operator optional<const T&>() const& noexcept
{
return this->has_value() ? optional<const T&>(**this) : optional<const T&>();
}
BOOST_CXX14_CONSTEXPR operator optional<T&>() && noexcept = delete;
BOOST_CONSTEXPR operator optional<const T&>() const&& noexcept = delete;
BOOST_CXX14_CONSTEXPR void reset() noexcept BOOST_CXX14_CONSTEXPR void reset() noexcept
{ {
storage.reset(); storage.reset();
@@ -521,9 +438,7 @@ 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)
{ {
@@ -539,7 +454,7 @@ namespace boost {
optional& operator=(F&& factory) optional& operator=(F&& factory)
{ {
reset(); reset();
boost_optional_detail::construct<value_type>(factory, this->dataptr()); factory.template apply<T>(this->dataptr());
storage.init_ = true; storage.init_ = true;
return *this; 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_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>
+1 -3
View File
@@ -28,6 +28,7 @@ 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
] ]
; ;
@@ -40,7 +41,6 @@ compile optional_test_constexpr.cpp ;
compile optional_test_wuninitialized.cpp ; compile optional_test_wuninitialized.cpp ;
compile optional_test_fwd_header.cpp ; compile optional_test_fwd_header.cpp ;
run optional_test_conversions_from_U.cpp ; run optional_test_conversions_from_U.cpp ;
run optional_test_constructors.cpp ;
run optional_test_convert_from_T.cpp ; run optional_test_convert_from_T.cpp ;
run optional_test_convert_assign.cpp ; run optional_test_convert_assign.cpp ;
run optional_test_empty_braces.cpp ; run optional_test_empty_braces.cpp ;
@@ -49,7 +49,6 @@ 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 ;
@@ -81,7 +80,6 @@ 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 ;
+1 -34
View File
@@ -20,16 +20,6 @@ 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;
@@ -62,7 +52,7 @@ namespace test_int
static_assert(o2 != o1, ""); static_assert(o2 != o1, "");
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> 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 = {};
@@ -98,29 +88,6 @@ namespace test_record
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;
-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> > 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
} }
-33
View File
@@ -105,42 +105,9 @@ 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,7 +32,6 @@ 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
@@ -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 struct Value
{ {
int val; int val;
BOOST_CONSTEXPR explicit Value(int v) : val(v) {} 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)
@@ -43,11 +37,6 @@ 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)
{ {
@@ -58,21 +47,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));
} }
@@ -81,121 +70,29 @@ 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()
{ {
@@ -203,21 +100,17 @@ 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();
} }