Compare commits

...

10 Commits

Author SHA1 Message Date
Andrzej Krzemienski 0fca17a0a8 GHA fix 3 2026-02-16 13:00:57 +01:00
Andrzej Krzemienski 3ce5e44ae2 GHA fix 2 2026-02-16 12:39:36 +01:00
Andrzej Krzemienski 64aa3f918c change GHA setup 2026-02-16 12:27:50 +01:00
Andrzej Krzemienski 003b1e5415 fix ranges triviality test on too old GCC 2026-02-10 19:12:41 +01:00
Andrzej Krzemienski d3f6501728 docs: operator bool fix 2026-02-10 01:54:32 +01:00
Andrzej Krzemienski 802715d295 add comparison for none and docs 2026-02-10 01:51:53 +01:00
Andrzej Krzemienski 437c1eb626 really fix the factory bug 2026-02-08 23:42:24 +01:00
Andrzej Krzemienski 6a2e169f23 fix conditional constexpr init in MSVC 2026-02-08 20:01:24 +01:00
Andrzej Krzemienski f0059887bc fix factory application syntax 2026-02-08 18:56:56 +01:00
Andrzej Krzemienski b8e5c07f2f fix constexpr tests 2026-02-08 12:15:52 +01:00
18 changed files with 277 additions and 32 deletions
+6 -1
View File
@@ -142,8 +142,9 @@ jobs:
- toolset: clang - toolset: clang
compiler: clang++-16 compiler: clang++-16
cxxstd: "03,11,14,17,20,2b" cxxstd: "03,11,14,17,20,2b"
os: ubuntu-24.04 os: ubuntu-latest
install: clang-16 install: clang-16
container: ubuntu:24.04
- toolset: clang - toolset: clang
compiler: clang++-17 compiler: clang++-17
cxxstd: "03,11,14,17,20,2b" cxxstd: "03,11,14,17,20,2b"
@@ -224,6 +225,10 @@ jobs:
cxxstd: 14,latest cxxstd: 14,latest
addrmd: 32,64 addrmd: 32,64
os: windows-2019 os: windows-2019
- toolset: msvc-14.1
cxxstd: "11,14,17,20,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2 - toolset: msvc-14.2
cxxstd: "14,17,20,latest" cxxstd: "14,17,20,latest"
addrmd: 32,64 addrmd: 32,64
+2 -2
View File
@@ -1,8 +1,8 @@
[library Boost.Optional [library Boost.Optional
[quickbook 1.4] [quickbook 1.7]
[authors [Cacciola Carballal, Fernando Luis]] [authors [Cacciola Carballal, Fernando Luis]]
[copyright 2003-2007 Fernando Luis Cacciola Carballal] [copyright 2003-2007 Fernando Luis Cacciola Carballal]
[copyright 2014-2026 Andrzej Krzemieński] [copyright 2014-2026 Andrzej Krzemieński]
[category miscellaneous] [category miscellaneous]
[id optional] [id optional]
[dirname optional] [dirname optional]
+3 -1
View File
@@ -27,7 +27,7 @@ rather than the reference itself.
On compilers that do not conform to Standard C++ rules of reference binding, On compilers that do not conform to Standard C++ rules of reference binding,
some operations on optional references are disabled in order to prevent subtle some operations on optional references are disabled in order to prevent subtle
bugs. For more details see bugs. For more details see
[link boost_optional.dependencies_and_portability.optional_reference_binding Dependencies and Portability section]. [link optional_reference_binding Dependencies and Portability section].
] ]
[heading Rvalue references] [heading Rvalue references]
@@ -39,6 +39,8 @@ Rvalue references and lvalue references to const have the ability in C++ to exte
[endsect] [endsect]
[#optional_ref_rebinding_semantics]
[section Rebinding semantics for assignment of optional references] [section Rebinding semantics for assignment of optional references]
If you assign to an ['uninitialized ] `optional<T&>` the effect is to bind (for If you assign to an ['uninitialized ] `optional<T&>` the effect is to bind (for
+2 -2
View File
@@ -1,5 +1,5 @@
[section In-Place Factories] [section:in_place_factories In-Place Factories][#boost_optional_factories]
One of the typical problems with wrappers and containers is that their One of the typical problems with wrappers and containers is that their
interfaces usually provide an operation to initialize or assign the interfaces usually provide an operation to initialize or assign the
@@ -138,4 +138,4 @@ The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYP
[caution The support for in-place factories is deprecated. Use constructor taking `in_place_init` tag and function `.emplace()` instead.] [caution The support for in-place factories is deprecated. Use constructor taking `in_place_init` tag and function `.emplace()` instead.]
[endsect] [endsect:in_place_factories]
+1 -1
View File
@@ -8,7 +8,7 @@ The very minimum requirement of `optional<T>` is that `T` is a complete type and
assert(!o); // assert(!o); //
o.value(); // always throws o.value(); // always throws
But this is practically useless. In order for `optional<T>` to be able to do anything useful and offer all the spectrum of ways of accessing the contained value, `T` needs to have at least one accessible constructor. In that case you need to initialize the optional object with function `emplace()`, or if your compiler does not support it, resort to [link boost_optional.design.in_place_factories In-Place Factories]: But this is practically useless. In order for `optional<T>` to be able to do anything useful and offer all the spectrum of ways of accessing the contained value, `T` needs to have at least one accessible constructor. In that case you need to initialize the optional object with function `emplace()`, or if your compiler does not support it, resort to [link boost_optional_factories In-Place Factories]:
optional<T> o; optional<T> o;
o.emplace("T", "ctor", "params"); o.emplace("T", "ctor", "params");
+14 -3
View File
@@ -2,7 +2,7 @@
Boost.Optional Boost.Optional
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
Copyright (c) 2015 Andrzej Krzemienski Copyright (c) 2015 Andrzej Krzemieński
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at (See accompanying file LICENSE_1_0.txt or copy at
@@ -15,14 +15,25 @@
``` ```
namespace boost { namespace boost {
class none_t {/* see below */}; class none_t
{
friend constexpr bool operator==(none_t, none_t) = default;
/* see below */
};
inline constexpr none_t none (/* see below */); inline constexpr none_t none (/* see below */);
} // namespace boost } // namespace boost
``` ```
Class `none_t` is meant to serve as a tag for selecting appropriate overloads of from `optional`'s interface. It is an empty, trivially copyable class with disabled default constructor. Class `none_t` is meant to serve as a tag for selecting appropriate overloads of from `optional`'s interface.
It is an empty class.
It is [@https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable.html trivially copyable].
It is ['not] [@https://en.cppreference.com/w/cpp/named_req/DefaultConstructible default-constructible].
It models concept [@https://en.cppreference.com/w/cpp/concepts/equality_comparable `std::equality_comparable`].
Constant `none` is used to indicate an optional object that does not contain a value in initialization, assignment and relational operations of `optional`. Constant `none` is used to indicate an optional object that does not contain a value in initialization, assignment and relational operations of `optional`.
+3 -3
View File
@@ -281,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.design.in_place_factories In-Place Factories] * [*Notes:] See [link boost_optional_factories In-Place Factories]
* [*Exception Safety:] Exceptions can only be thrown during the call to * [*Exception Safety:] Exceptions can only be thrown during the call to
the `T` constructor used by the factory; in that case, this constructor has the `T` constructor used by the factory; in that case, this constructor has
no effect. no effect.
@@ -524,7 +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.design.in_place_factories In-Place Factories] * [*Notes:] See [link boost_optional_factories In-Place Factories]
* [*Exception Safety:] Exceptions can only be thrown during the call to * [*Exception Safety:] Exceptions can only be thrown during the call to
the `T` constructor used by the factory; in that case, the `optional` object the `T` constructor used by the factory; in that case, the `optional` object
will be reset to be ['uninitialized]. will be reset to be ['uninitialized].
@@ -956,7 +956,7 @@ __SPACE__
* [*Postconditions:] `bool(*this) == bool(rhs)`. * [*Postconditions:] `bool(*this) == bool(rhs)`.
* [*Notes:] This behaviour is called ['rebinding semantics]. See [link boost_optional.design.optional_references.rebinding_semantics_for_assignment_of_optional_references here] for details. * [*Notes:] This behaviour is called ['rebinding semantics]. See [link optional_ref_rebinding_semantics here] for details.
* [*Example:] * [*Example:]
`` ``
+1 -1
View File
@@ -11,7 +11,7 @@
[section Header <boost/optional.hpp>] [section Header <boost/optional.hpp>]
This is an alias for header [link boost_optional.reference.header__boost_optional_optional_hpp_.header_optional_optional `<boost/optional/optional.hpp>`]. This is an alias for header [link ref_header_optional_optional_hpp `<boost/optional/optional.hpp>`].
[endsect] [endsect]
+45 -3
View File
@@ -13,13 +13,55 @@
[section Minimum System Requirements] [section Minimum System Requirements]
This library requires C++11 as minimum. However some features are disabled. This library requires C++11 as minimum. However, in C++11 some features are disabled.
For C++14 and higher this library provides a `constexpr` interface for non-mutable [section:constexpr Support for `constexpr`]
member functions and some mutable member functions.
[section C++11]
For compilers fully supporting C++11 (including unconstrained unions and ref-qualifiers),
for trivially-destructible `T`s, `optional<T>` is a ['literal type] and its constructors
with `this->has_value() == false` as postcondition:
* `optional()`,
* `optional(none_t)`,
are ['core constant expressions]. Even for other `T`s, these constructors are guaranteed to
perform ['constant initialization]: they are never subject to "initialization order fiasco".
Other constructors with `this->has_value() == true`
as postcondition are core constant expressions if the expression required to initialize
the contained value is a core constant expression. This includes constructors:
* `template <typename... Args> optional(in_place_init, Args&&...)`,
* `template <typename U> optional(U&&)`,
* `optional(const T&)`,
* `optional(T&&)`.
Other constructors, including the copy and move constructos, are ['not] core constant expressions.
Member functions `.has_value`, `operator bool` and (non)equality comparisons with `none` are core-constant expressions for trivially-destructible `T`s.
Also all `const`-qualified non-static member functions and comparison operators are core constant expressions, if the corresponding operations on `T`
are core constant expressions.
[endsect]
[section C++14]
For C++14 and higher this library, for trivially-destructible `T`s provides the `constexpr` interface for all mutable and non-mutable
member functions, as long as:
* the corresponding operations on `T` are core constant expressions and
* the member never attempts to change the `optional`'s state from not containing a value to containing a value.
[note For types that overload unary `operator&` (address) some member functions in `optional`, like `operator->`, [note For types that overload unary `operator&` (address) some member functions in `optional`, like `operator->`,
cannot be implemented as `constexpr` on some compilers.] cannot be implemented as `constexpr` on some compilers.]
[endsect]
[section C++17]
In C++17 all non-deprecated constructors are core constant expressions as long as
`T` is a literal type and its constructor used is a core constant expression.
[endsect]
[endsect:constexpr]
[endsect] [endsect]
+7 -2
View File
@@ -11,8 +11,7 @@
[section:std_comp Comparison with `std::optional`] [section:std_comp Comparison with `std::optional`]
[table [table Comparison with `std::optional`
[]
[ [[*`boost::optional`]] [[*`std::optional`]] [] ] [ [[*`boost::optional`]] [[*`std::optional`]] [] ]
[ [`optional<int> o = none;`] [`optional<int> o = nullopt;`] [Different name for no-value tag.] ] [ [`optional<int> o = none;`] [`optional<int> o = nullopt;`] [Different name for no-value tag.] ]
[ [`optional<X> o {in_place_init, a, b};`] [`optional<int> o {in_place, a, b};`] [Different name for in-place initialization tag.] ] [ [`optional<X> o {in_place_init, a, b};`] [`optional<int> o {in_place, a, b};`] [Different name for in-place initialization tag.] ]
@@ -42,6 +41,12 @@
[ [`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`. ] ]
] ]
+26
View File
@@ -11,9 +11,35 @@
[section:relnotes Release Notes] [section:relnotes Release Notes]
[heading Boost Release 1.91]
* For compilers with full C++11 support (including "unrestricted unions" and ref-qualifiers)
changed the implementation from aligned storage to union storage. This enables the gradual
`constexpr` support:
* In C++11, some constructors and `const`-qualified accessors become usable
in compile-time contexts (are ['core constant expressions] for types
satisfying certain constraints.
* In C++14 even some mutating operations become core constant expressions (those
that do not require changing the state of `optional` from not having a value to
having a value), for co-operating types.
* In C++17 all constructors (including copy and move) become core constant expressions
for co-operating types.
This addresses [@https://github.com/boostorg/optional/issues/143 issue #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`.
* `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.
[heading Boost Release 1.87] [heading Boost Release 1.87]
+6 -1
View File
@@ -25,7 +25,7 @@
#elif defined(BOOST_NO_CXX11_REF_QUALIFIERS) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DEFAULTED_MOVES) #elif defined(BOOST_NO_CXX11_REF_QUALIFIERS) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Optional 1.83 and will be removed in Boost.Optional 1.88.") BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Optional 1.83 and will be removed in Boost.Optional 1.92.")
#endif #endif
@@ -46,6 +46,11 @@ struct none_t
{ {
struct init_tag{}; struct init_tag{};
explicit BOOST_CONSTEXPR none_t(init_tag){} // to disable default constructor explicit BOOST_CONSTEXPR none_t(init_tag){} // to disable default constructor
#ifndef BOOST_OPTIONAL_DISABLE_EQUALITY_FOR_NONE
friend BOOST_CONSTEXPR bool operator==(none_t, none_t) { return true; }
friend BOOST_CONSTEXPR bool operator!=(none_t, none_t) { return false; }
#endif
}; };
#endif // old implementation workarounds #endif // old implementation workarounds
@@ -22,6 +22,7 @@
#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>
@@ -195,6 +195,31 @@ namespace boost {
storage.init_ = true; storage.init_ = true;
} }
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
// The conditional initialization of storage needs to employ a factory
// function, so that we can utilize the guaranteed copy elision on the
// return type.
// an alternative -- using a conditional operator in the initializer --
// does not work in MSVC 14.2 and 14.3.
template <typename... U>
static constexpr storage_t conditional_storage_from_values(bool cond, U&&... v)
{
if (cond)
return storage_t(in_place_init, optional_detail::forward_<U>(v)...);
else
return storage_t();
}
template <typename OU>
static constexpr storage_t conditional_storage_from_optional(OU&& ou)
{
if (ou.has_value())
return storage_t(in_place_init, *optional_detail::forward_<OU>(ou));
else
return storage_t();
}
#endif
public: public:
using value_type = T; using value_type = T;
using unqualified_value_type = typename ::std::remove_const<T>::type; using unqualified_value_type = typename ::std::remove_const<T>::type;
@@ -218,35 +243,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(cond ? storage_t(v) : storage_t()) : storage(conditional_storage_from_values(cond, v))
{} {}
constexpr optional(bool cond, T&& v) constexpr optional(bool cond, T&& v)
: storage(cond ? storage_t(optional_detail::move_(v)) : storage_t()) : storage(conditional_storage_from_values(cond, optional_detail::move_(v)))
{} {}
constexpr optional(const optional& rhs) constexpr optional(const optional& rhs)
: storage(rhs.is_initialized() ? storage_t(*rhs) : storage_t()) : storage(conditional_storage_from_optional(rhs))
{} {}
constexpr optional(optional&& rhs) constexpr optional(optional&& rhs)
noexcept(::std::is_nothrow_move_constructible<T>::value) noexcept(::std::is_nothrow_move_constructible<T>::value)
: storage(rhs.is_initialized() ? storage_t(*optional_detail::move_(rhs)) : storage_t()) : storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
{} {}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)> template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)>
constexpr explicit optional(optional<U> const& rhs) constexpr explicit optional(optional<U> const& rhs)
: storage(rhs.is_initialized() ? storage_t(in_place_init, *rhs) : storage_t()) : storage(conditional_storage_from_optional(rhs))
{} {}
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)> template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
constexpr explicit optional(optional<U> && rhs) constexpr explicit optional(optional<U> && rhs)
: storage(rhs.is_initialized() ? storage_t(in_place_init, *optional_detail::move_(rhs)) : storage_t()) : storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
{} {}
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( cond ? storage_t(in_place_init, optional_detail::forward_<Args>(args)...) : storage_t() ) : storage(conditional_storage_from_values(cond, optional_detail::forward_<Args>(args)...))
{} {}
#else #else
optional(bool cond, const T& v) optional(bool cond, const T& v)
@@ -319,7 +344,7 @@ namespace boost {
explicit optional (FT&& factory) explicit optional (FT&& factory)
: storage() : storage()
{ {
factory.template apply<T>(this->dataptr()); boost_optional_detail::construct<value_type>(factory, this->dataptr());
storage.init_ = true; storage.init_ = true;
} }
@@ -454,7 +479,7 @@ namespace boost {
optional& operator=(F&& factory) optional& operator=(F&& factory)
{ {
reset(); reset();
factory.template apply<T>(this->dataptr()); boost_optional_detail::construct<value_type>(factory, this->dataptr());
storage.init_ = true; storage.init_ = true;
return *this; return *this;
} }
-2
View File
@@ -84,10 +84,8 @@ operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optiona
#include <boost/type_traits/is_volatile.hpp> #include <boost/type_traits/is_volatile.hpp>
#include <boost/type_traits/is_scalar.hpp> #include <boost/type_traits/is_scalar.hpp>
#include <boost/optional/optional_fwd.hpp> #include <boost/optional/optional_fwd.hpp>
#include <boost/optional/detail/optional_config.hpp> #include <boost/optional/detail/optional_config.hpp>
#include <boost/optional/detail/optional_factory_support.hpp>
#include <boost/optional/detail/optional_aligned_storage.hpp> #include <boost/optional/detail/optional_aligned_storage.hpp>
+1
View File
@@ -49,6 +49,7 @@ run optional_test_flat_map.cpp ;
run optional_test_hash.cpp ; run optional_test_hash.cpp ;
run optional_test_map.cpp ; run optional_test_map.cpp ;
run optional_test_tie.cpp : : : <library>/boost/tuple//boost_tuple ; run optional_test_tie.cpp : : : <library>/boost/tuple//boost_tuple ;
run optional_test_ranges_find.cpp ;
run optional_test_ref_assign_portable_minimum.cpp ; run optional_test_ref_assign_portable_minimum.cpp ;
run optional_test_ref_assign_mutable_int.cpp ; run optional_test_ref_assign_mutable_int.cpp ;
run optional_test_ref_assign_const_int.cpp ; run optional_test_ref_assign_const_int.cpp ;
+55 -1
View File
@@ -10,6 +10,7 @@
// akrzemi1@gmail.com // akrzemi1@gmail.com
#include "boost/optional.hpp" #include "boost/optional.hpp"
#include <string>
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION #ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
@@ -20,6 +21,16 @@ 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;
@@ -52,7 +63,7 @@ namespace test_int
static_assert(o2 != o1, ""); static_assert(o2 != o1, "");
static_assert(o2 > o1, ""); static_assert(o2 > o1, "");
#ifndef BOOST_NO_CXX14_CONSTEXPR #ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
constexpr boost::optional<int> oNc = oN; constexpr boost::optional<int> oNc = oN;
constexpr boost::optional<int> oNd = boost::none; constexpr boost::optional<int> oNd = boost::none;
constexpr boost::optional<int> oNe = {}; constexpr boost::optional<int> oNe = {};
@@ -88,6 +99,29 @@ 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;
@@ -96,4 +130,24 @@ namespace test_optional_ref
static_assert(*iref == 9, ""); static_assert(*iref == 9, "");
} }
namespace test_msvc_14_1
{
struct Aggr
{
boost::optional<std::string> os;
};
void test()
{
Aggr a;
Aggr b = a;
b = a;
Aggr c = Aggr();
b = Aggr();
(void)a;
(void)b;
(void)c;
}
}
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION #endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
+70
View File
@@ -0,0 +1,70 @@
// Copyright (C) 2026 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// akrzemi1@gmail.com
#include "boost/optional/optional.hpp"
#include "boost/core/lightweight_test.hpp"
#include <type_traits>
#ifndef BOOST_NO_CXX20_HDR_RANGES
#include <ranges>
#include <concepts>
#include <iterator>
#include <array>
#include <string>
static_assert(std::equality_comparable<boost::none_t>, "boost::none shall be equality comparable");
template <typename T>
void test_that_you_can_find_none_in_a_range_of_optional(T x, T y)
{
static_assert(std::equality_comparable_with<boost::optional<T>, boost::none_t>, "boost::none shall satisfy the concept");
static_assert(std::equality_comparable_with<boost::none_t, boost::optional<T> >, "boost::none shall satisfy the concept");
static_assert(std::indirect_binary_predicate<std::ranges::equal_to, const boost::optional<T>*, const boost::none_t*>, "boost::none shall satisfy the concept");
// [0] [1] [2]
std::array<boost::optional<T>, 3> arr = {{ x, boost::none, y }};
auto it = std::ranges::find(arr, boost::none);
BOOST_TEST_EQ(std::distance(arr.begin(), it), 1);
}
#endif // BOOST_NO_CXX20_HDR_RANGES
# if (defined __GNUC__) && (!defined BOOST_INTEL_CXX_VERSION) && (!defined __clang__)
# if (__GNUC__ <= 4)
# define BOOST_OPTIONAL_TEST_INSUFFICIENT_TYPE_TRAIT_SUPPORT
# endif
# endif
#ifndef BOOST_OPTIONAL_TEST_INSUFFICIENT_TYPE_TRAIT_SUPPORT
static_assert(std::is_trivially_copyable<boost::none_t>::value, "boost::none shall be trivially copyable");
#endif
void test_that_none_is_equal_to_none()
{
BOOST_TEST(boost::none == boost::none);
BOOST_TEST(!(boost::none != boost::none));
auto None = boost::none;
BOOST_TEST(None == boost::none);
BOOST_TEST(!(None != boost::none));
}
int main()
{
#ifndef BOOST_NO_CXX20_HDR_RANGES
test_that_you_can_find_none_in_a_range_of_optional(1, 2);
test_that_you_can_find_none_in_a_range_of_optional<std::string>("one", "two");
#endif
test_that_none_is_equal_to_none();
return boost::report_errors();
}