mirror of
https://github.com/boostorg/optional.git
synced 2026-06-11 20:01:10 +02:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8bc4a16933 | |||
| ecb241a919 | |||
| ff710d113c | |||
| 88e2378c8a | |||
| aaabe89a69 | |||
| fa52755c88 | |||
| 76be15bfeb | |||
| 5d8e50a9aa | |||
| 37513ddbbf | |||
| d46b9c3f77 | |||
| 953b678b39 | |||
| b2057c8dfe | |||
| 1c13f5f724 | |||
| aa1cf1e76c | |||
| 938502da88 | |||
| 046357ce54 | |||
| b6a57cdb46 | |||
| dd0e9d8a72 | |||
| c81b9b098b | |||
| 7b078be18d | |||
| 3df23370e6 | |||
| 881bf8da26 | |||
| bfdf0c73f9 | |||
| e1c6b5b737 | |||
| 1a8c2dcafd | |||
| 6134d0c274 | |||
| 121f3efde9 | |||
| e210740301 | |||
| c716bc552b | |||
| 5ad8b01512 | |||
| d5a0e294a7 | |||
| eab3caf7ed | |||
| b8fd0bcb5f | |||
| 86f3288312 | |||
| 5e7fdf5ec5 | |||
| e601f1ef2d | |||
| b2c7f93ead | |||
| c8bd18d6de | |||
| 7974207c7f | |||
| c33708c1f9 | |||
| 2b33d57c82 | |||
| 76200db7c4 | |||
| cfcd23d55b | |||
| 825f38f5b5 | |||
| cacde054df | |||
| 1820ae55ef | |||
| f91e03b35b | |||
| ae15fc54b2 | |||
| dc7909db4a | |||
| 1825c778ed | |||
| f97e43ce13 | |||
| cb68f6053d | |||
| 07b689fc3e | |||
| cbfb66379b | |||
| c1519884ed | |||
| 19f202b650 | |||
| 4ce395e14d | |||
| 1ceb5004da | |||
| 942caa437b | |||
| 824552dc5f | |||
| c74b5e1e29 | |||
| cbc7014edf | |||
| 6fa214e0a6 | |||
| 87586cd9b1 | |||
| cc54a71150 | |||
| 8ecf840c33 | |||
| c6657cc9bd | |||
| ce03067859 | |||
| c3b5267506 | |||
| 5fa59b9a35 | |||
| e1a3501a78 | |||
| 36c33f2e67 | |||
| 411ead088d | |||
| e360de3da5 | |||
| 346dc03746 | |||
| 27309c40ad | |||
| 6ec468aff6 | |||
| 794e03af30 | |||
| 3a8556186e | |||
| 82d08adf11 | |||
| 4c503758fe | |||
| bf10cf91c2 | |||
| dfe1915930 | |||
| 8ffcf0f369 | |||
| 0473d0a56c | |||
| 8421c07517 | |||
| 22657e9c6e | |||
| 6bd32078b4 | |||
| 9a2c5ec37b | |||
| 1f473d2596 | |||
| 81f4543d81 | |||
| 7ed6bf5bca | |||
| b7a1d666f1 |
+16
-20
@@ -58,7 +58,7 @@ jobs:
|
||||
address-model: 32,64
|
||||
- toolset: gcc-11
|
||||
cxxstd: "03,11,14,17,20"
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
install: g++-11-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-12
|
||||
@@ -68,8 +68,7 @@ jobs:
|
||||
address-model: 32,64
|
||||
- toolset: gcc-13
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:23.04
|
||||
os: ubuntu-24.04
|
||||
install: g++-13-multilib
|
||||
address-model: 32,64
|
||||
- toolset: clang
|
||||
@@ -143,40 +142,40 @@ jobs:
|
||||
- toolset: clang
|
||||
compiler: clang++-16
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
container: ubuntu:23.04
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-24.04
|
||||
install: clang-16
|
||||
- toolset: clang
|
||||
compiler: clang++-17
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
container: ubuntu:23.10
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-24.04
|
||||
install: clang-17
|
||||
- toolset: clang
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: macos-11
|
||||
- toolset: clang
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: macos-12
|
||||
- toolset: clang
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
os: macos-13
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
container: ${{matrix.container}}
|
||||
container:
|
||||
image: ${{matrix.container}}
|
||||
volumes:
|
||||
- /node20217:/node20217:rw,rshared
|
||||
- ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup container environment
|
||||
if: matrix.container
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get -y install sudo python3 git g++
|
||||
apt-get -y install sudo python3 git g++ curl
|
||||
if [[ "${{matrix.container}}" == "ubuntu:1"* ]]; then
|
||||
# Node 20 doesn't work with Ubuntu 16/18 glibc: https://github.com/actions/checkout/issues/1590
|
||||
curl -sL https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz | tar -xJ --strip-components 1 -C /node20217
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
@@ -282,7 +281,6 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
- os: macos-12
|
||||
- os: macos-13
|
||||
|
||||
@@ -330,7 +328,6 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
- os: macos-12
|
||||
- os: macos-13
|
||||
|
||||
@@ -388,7 +385,6 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
- os: macos-12
|
||||
- os: macos-13
|
||||
|
||||
|
||||
+5
-4
@@ -11,19 +11,20 @@ add_library(boost_optional INTERFACE)
|
||||
add_library(Boost::optional ALIAS boost_optional)
|
||||
|
||||
target_include_directories(boost_optional INTERFACE include)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS "3.19")
|
||||
file(GLOB_RECURSE headers include/*.hpp)
|
||||
target_sources(boost_optional PRIVATE ${headers})
|
||||
endif()
|
||||
|
||||
target_link_libraries(boost_optional
|
||||
INTERFACE
|
||||
Boost::assert
|
||||
Boost::config
|
||||
Boost::core
|
||||
Boost::move
|
||||
Boost::predef
|
||||
Boost::static_assert
|
||||
Boost::throw_exception
|
||||
Boost::type_traits
|
||||
Boost::utility
|
||||
)
|
||||
target_compile_features(boost_optional INTERFACE cxx_std_11)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Copyright René Ferdinand Rivera Morell 2023-2024
|
||||
# Distributed under 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)
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
constant boost_dependencies :
|
||||
/boost/assert//boost_assert
|
||||
/boost/config//boost_config
|
||||
/boost/core//boost_core
|
||||
/boost/throw_exception//boost_throw_exception
|
||||
/boost/type_traits//boost_type_traits ;
|
||||
|
||||
project /boost/optional ;
|
||||
|
||||
explicit
|
||||
[ alias boost_optional : : : : <library>$(boost_dependencies) <include>include ]
|
||||
[ alias all : boost_optional test ]
|
||||
;
|
||||
|
||||
call-if : boost-library optional
|
||||
;
|
||||
+20
-12
@@ -1,8 +1,8 @@
|
||||
[library Boost.Optional
|
||||
[quickbook 1.4]
|
||||
[quickbook 1.7]
|
||||
[authors [Cacciola Carballal, Fernando Luis]]
|
||||
[copyright 2003-2007 Fernando Luis Cacciola Carballal]
|
||||
[copyright 2014-2024 Andrzej Krzemieński]
|
||||
[copyright 2014-2026 Andrzej Krzemieński]
|
||||
[category miscellaneous]
|
||||
[id optional]
|
||||
[dirname optional]
|
||||
@@ -49,12 +49,18 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
[def __SPACE__ [$images/space.png]]
|
||||
[def __GO_TO__ [$images/R.png]]
|
||||
|
||||
[/ Common terms ]
|
||||
|
||||
[def __UB__ [@https://en.cppreference.com/w/cpp/language/ub ['undefined behavior]]]
|
||||
|
||||
|
||||
[section Introduction]
|
||||
Class template `optional` is a wrapper for representing 'optional' (or 'nullable') objects who may not (yet) contain a valid value. Optional objects offer full value semantics; they are good for passing by value and usage inside STL containers. This is a header-only library.
|
||||
Class template `optional` is a wrapper for representing 'optional' (or 'nullable')
|
||||
objects who may not (yet) contain a valid value. Optional objects offer full value semantics;
|
||||
they are good for passing by value and usage inside STL containers. This is a header-only C++11 library.
|
||||
|
||||
[heading Problem]
|
||||
Suppose we want to read a parameter form a config file which represents some integral value, let's call it `"MaxValue"`. It is possible that this parameter is not specified; such situation is no error. It is valid to not specify the parameter and in that case the program is supposed to behave slightly differently. Also, suppose that any possible value of type `int` is a valid value for `"MaxValue"`, so we cannot just use `-1` to represent the absence of the parameter in the config file.
|
||||
Suppose we want to read a parameter from a config file which represents some integral value, let's call it `"MaxValue"`. It is possible that this parameter is not specified; such situation is no error. It is valid to not specify the parameter and in that case the program is supposed to behave slightly differently. Also, suppose that any possible value of type `int` is a valid value for `"MaxValue"`, so we cannot just use `-1` to represent the absence of the parameter in the config file.
|
||||
|
||||
[heading Solution]
|
||||
|
||||
@@ -75,19 +81,16 @@ This is how you solve it with `boost::optional`:
|
||||
[endsect]
|
||||
|
||||
[include 01_quick_start.qbk]
|
||||
[section Tutorial]
|
||||
[include 10_motivation.qbk]
|
||||
[section:design Design Overview and Rationale]
|
||||
[include 11_development.qbk]
|
||||
[include 12_when_to_use.qbk]
|
||||
[include 13_relational_operators.qbk]
|
||||
[include 14_monadic_interface.qbk]
|
||||
[include 12_relational_operators.qbk]
|
||||
[include 13_convenience.qbk]
|
||||
[include 15_io.qbk]
|
||||
[include 16_optional_references.qbk]
|
||||
[include 17_in_place_factories.qbk]
|
||||
[include 18_gotchas.qbk]
|
||||
[include 19_exception_safety.qbk]
|
||||
[include 1A_type_requirements.qbk]
|
||||
[include 1B_on_performance.qbk]
|
||||
[endsect]
|
||||
[section:reference Reference]
|
||||
[include 21_ref_none.qbk]
|
||||
@@ -100,6 +103,11 @@ This is how you solve it with `boost::optional`:
|
||||
[endsect]
|
||||
[include 29_ref_optional_convenience.qbk]
|
||||
[endsect]
|
||||
[section:advice Advice]
|
||||
[include 31_when_to_use.qbk]
|
||||
[include 32_on_performance.qbk]
|
||||
[endsect]
|
||||
[include 90_dependencies.qbk]
|
||||
[include 91_relnotes.qbk]
|
||||
[include 92_acknowledgments.qbk]
|
||||
[include 91_comparison_with_std.qbk]
|
||||
[include 92_relnotes.qbk]
|
||||
[include 93_acknowledgments.qbk]
|
||||
|
||||
+57
-23
@@ -10,16 +10,24 @@
|
||||
]
|
||||
|
||||
|
||||
[section Quick Start]
|
||||
[section Quick Overview]
|
||||
|
||||
[section Optional return values]
|
||||
|
||||
Let's write and use a converter function that converts a `std::string` to an `int`. It is possible that for a given string (e.g. `"cat"`) there exists no value of type `int` capable of representing the conversion result. We do not consider such situation an error. We expect that the converter can be used only to check if the conversion is possible. A natural signature for this function can be:
|
||||
Let's write and use a converter function that converts a `std::string` to an `int`.
|
||||
It is possible that for a given string (e.g. `"cat"`) there exists no value of type
|
||||
`int` capable of representing the conversion result. We do not consider such
|
||||
situation an error. We expect that the converter can be used only to check if
|
||||
the conversion is possible. A natural signature for this function can be:
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
boost::optional<int> convert(const std::string& text);
|
||||
|
||||
All necessary functionality can be included with one header `<boost/optional.hpp>`. The above function signature means that the function can either return a value of type `int` or a flag indicating that no value of `int` is available. This does not indicate an error. It is like one additional value of `int`. This is how we can use our function:
|
||||
All necessary functionality can be included with one header `<boost/optional.hpp>`.
|
||||
The above function signature means that the function can either return a value
|
||||
of type `int` or a flag indicating that no value of `int` is available.
|
||||
This does not indicate an error. It is like one additional value of `int`.
|
||||
This is how we can use our function:
|
||||
|
||||
const std::string& text = /*... */;
|
||||
boost::optional<int> oi = convert(text); // move-construct
|
||||
@@ -116,29 +124,9 @@ Suppose we want to implement a ['lazy load] optimization. This is because we do
|
||||
|
||||
`optional`'s default constructor creates an uninitialized optional. No call to `Resource`'s default constructor is attempted. `Resource` doesn't have to be __STD_DEFAULT_CONSTRUCTIBLE__. In function `getResource` we first check if `resource_` is initialized. This time we do not use the contextual conversion to `bool`, but a comparison with `boost::none`. These two ways are equivalent. Function `emplace` initializes the optional in-place by perfect-forwarding the arguments to the constructor of `Resource`. No copy- or move-construction is involved here. `Resource` doesn't even have to be `MoveConstructible`.
|
||||
|
||||
[note Function `emplace` is only available on compilers that support rvalue references and variadic templates. If your compiler does not support these features and you still need to avoid any move-constructions, use [link boost_optional.tutorial.in_place_factories In-Place Factories].]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Bypassing unnecessary default construction]
|
||||
|
||||
Suppose we have class `Date`, which does not have a default constructor: there is no good candidate for a default date. We have a function that returns two dates in form of a `boost::tuple`:
|
||||
|
||||
boost::tuple<Date, Date> getPeriod();
|
||||
|
||||
In other place we want to use the result of `getPeriod`, but want the two dates to be named: `begin` and `end`. We want to implement something like 'multiple return values':
|
||||
|
||||
Date begin, end; // Error: no default ctor!
|
||||
boost::tie(begin, end) = getPeriod();
|
||||
|
||||
The second line works already, this is the capability of __BOOST_TUPLE__ library, but the first line won't work. We could set some invented initial dates, but it is confusing and may be an unacceptable cost, given that these values will be overwritten in the next line anyway. This is where `optional` can help:
|
||||
|
||||
boost::optional<Date> begin, end;
|
||||
boost::tie(begin, end) = getPeriod();
|
||||
|
||||
It works because inside `boost::tie` a move-assignment from `T` is invoked on `optional<T>`, which internally calls a move-constructor of `T`.
|
||||
[endsect]
|
||||
|
||||
[section Storage in containers]
|
||||
|
||||
Suppose you want to ask users to choose some number (an `int`). One of the valid responses is to choose nothing, which is represented by an uninitialized `optional<int>`. You want to make a histogram showing how many times each choice was made. You can use an `std::map`:
|
||||
@@ -157,4 +145,50 @@ which is compared less than any value of `T`.
|
||||
as it provides specializations for `std::hash`.
|
||||
[endsect]
|
||||
|
||||
[section Monadic interface]
|
||||
|
||||
The monadic interface of `optional` allows the application of functions
|
||||
to optional values without resorting to the usage of explicit `if`-statements.
|
||||
|
||||
Function `map` takes a function mapping type `T` onto type `U` and maps an `optional<T>`
|
||||
onto an `optional<U>` using the provided function.
|
||||
|
||||
int length(const string& s){ return s.size(); };
|
||||
|
||||
optional<string> null{}, thin{""}, word{"word"};
|
||||
assert (null.map(length) == none);
|
||||
assert (thin.map(length) == 0);
|
||||
assert (word.map(length) == 4);
|
||||
|
||||
Function `flat_map` is similar, but it requires the function to return an
|
||||
`optional<V>` for some type `V`. This `optional<V>` becomes the return type of
|
||||
`flat_map`.
|
||||
|
||||
optional<char> first_char(const string& s) {
|
||||
if (s.empty()) return none;
|
||||
else return s[0];
|
||||
};
|
||||
|
||||
optional<string> null{}, thin{""}, word{"word"};
|
||||
assert (null.flat_map(first_char) == none);
|
||||
assert (thin.flat_map(first_char) == none);
|
||||
assert (word.flat_map(first_char) == 'w');
|
||||
|
||||
These functions can be combined in one expression reflecting a chain of computations:
|
||||
|
||||
auto get_contents(path p) -> optional<string>;
|
||||
auto trim(string) -> string;
|
||||
auto length(string) -> int;
|
||||
|
||||
auto trimmed_size_of(optional<path> p) -> int
|
||||
{
|
||||
return p.flat_map(get_contents)
|
||||
.map(trim)
|
||||
.map(length)
|
||||
.value_or(0);
|
||||
}
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
[/
|
||||
Boost.Optional
|
||||
|
||||
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
|
||||
Copyright (c) 2014 Andrzej Krzemienski
|
||||
|
||||
Distributed under 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)
|
||||
]
|
||||
|
||||
[section Motivation]
|
||||
|
||||
Consider these functions which should return a value but which might not have
|
||||
a value to return:
|
||||
|
||||
* (A) `double sqrt(double n );`
|
||||
* (B) `char get_async_input();`
|
||||
* (C) `point polygon::get_any_point_effectively_inside();`
|
||||
|
||||
There are different approaches to the issue of not having a value to return.
|
||||
|
||||
A typical approach is to consider the existence of a valid return value as a
|
||||
postcondition, so that if the function cannot compute the value to return, it
|
||||
has either undefined behavior (and can use assert in a debug build) or uses a
|
||||
runtime check and throws an exception if the postcondition is violated. This
|
||||
is a reasonable choice for example, for function (A), because the lack of a
|
||||
proper return value is directly related to an invalid parameter (out of domain
|
||||
argument), so it is appropriate to require the callee to supply only parameters
|
||||
in a valid domain for execution to continue normally.
|
||||
|
||||
However, function (B), because of its asynchronous nature, does not fail just
|
||||
because it can't find a value to return; so it is incorrect to consider such
|
||||
a situation an error and assert or throw an exception. This function must
|
||||
return, and somehow, must tell the callee that it is not returning a meaningful
|
||||
value.
|
||||
|
||||
A similar situation occurs with function (C): it is conceptually an error to
|
||||
ask a ['null-area] polygon to return a point inside itself, but in many
|
||||
applications, it is just impractical for performance reasons to treat this as
|
||||
an error (because detecting that the polygon has no area might be too expensive
|
||||
to be required to be tested previously), and either an arbitrary point
|
||||
(typically at infinity) is returned, or some efficient way to tell the callee
|
||||
that there is no such point is used.
|
||||
|
||||
There are various mechanisms to let functions communicate that the returned
|
||||
value is not valid. One such mechanism, which is quite common since it has
|
||||
zero or negligible overhead, is to use a special value which is reserved to
|
||||
communicate this. Classical examples of such special values are `EOF`,
|
||||
`string::npos`, points at infinity, etc...
|
||||
|
||||
When those values exist, i.e. the return type can hold all meaningful values
|
||||
['plus] the ['signal] value, this mechanism is quite appropriate and well known.
|
||||
Unfortunately, there are cases when such values do not exist. In these cases,
|
||||
the usual alternative is either to use a wider type, such as `int` in place of
|
||||
`char`; or a compound type, such as `std::pair<point,bool>`.
|
||||
|
||||
Returning a `std::pair<T,bool>`, thus attaching a boolean flag to the result
|
||||
which indicates if the result is meaningful, has the advantage that can be
|
||||
turned into a consistent idiom since the first element of the pair can be
|
||||
whatever the function would conceptually return. For example, the last two
|
||||
functions could have the following interface:
|
||||
|
||||
std::pair<char,bool> get_async_input();
|
||||
std::pair<point,bool> polygon::get_any_point_effectively_inside();
|
||||
|
||||
These functions use a consistent interface for dealing with possibly nonexistent
|
||||
results:
|
||||
|
||||
std::pair<point,bool> p = poly.get_any_point_effectively_inside();
|
||||
if ( p.second )
|
||||
flood_fill(p.first);
|
||||
|
||||
However, not only is this quite a burden syntactically, it is also error prone
|
||||
since the user can easily use the function result (first element of the pair)
|
||||
without ever checking if it has a valid value.
|
||||
|
||||
Clearly, we need a better idiom.
|
||||
|
||||
[endsect]
|
||||
+114
-223
@@ -2,250 +2,141 @@
|
||||
Boost.Optional
|
||||
|
||||
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
|
||||
Copyright (c) 2024 andrzej Krzemieński
|
||||
|
||||
Distributed under 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)
|
||||
]
|
||||
|
||||
[section Design Overview]
|
||||
[section Design Goals]
|
||||
|
||||
[section The models]
|
||||
In C++ you can create an automatic object of a scalar type, and manipulate it,
|
||||
without assigning it the initial value.
|
||||
|
||||
In C++, we can ['declare] an object (a variable) of type `T`, and we can give this
|
||||
variable an ['initial value] (through an ['initializer]. (cf. 8.5)).
|
||||
When a declaration includes a non-empty initializer (an initial value is given),
|
||||
it is said that the object has been initialized.
|
||||
If the declaration uses an empty initializer (no initial value is given), and
|
||||
neither default nor value initialization applies, it is said that the object is
|
||||
[*uninitialized]. Its actual value exist but has an ['indeterminate initial value]
|
||||
(cf. 8.5/11).
|
||||
`optional<T>` intends to formalize the notion of initialization (or lack of it)
|
||||
allowing a program to test whether an object has been initialized and stating
|
||||
that access to the value of an uninitialized object is undefined behavior. That
|
||||
is, when a variable is declared as `optional<T>` and no initial value is given,
|
||||
the variable is ['formally] uninitialized. A formally uninitialized optional object
|
||||
has conceptually no value at all and this situation can be tested at runtime. It
|
||||
is formally ['undefined behavior] to try to access the value of an uninitialized
|
||||
optional. An uninitialized optional can be assigned a value, in which case its initialization state changes to initialized. Furthermore, given the formal
|
||||
treatment of initialization states in optional objects, it is even possible to
|
||||
reset an optional to ['uninitialized].
|
||||
{
|
||||
int i; // indeterminate value
|
||||
populate(&i);
|
||||
cout << i;
|
||||
}
|
||||
|
||||
In C++ there is no formal notion of uninitialized objects, which means that
|
||||
objects always have an initial value even if indeterminate.
|
||||
As discussed on the previous section, this has a drawback because you need
|
||||
additional information to tell if an object has been effectively initialized.
|
||||
One of the typical ways in which this has been historically dealt with is via
|
||||
a special value: `EOF`, `npos`, -1, etc... This is equivalent to adding the
|
||||
special value to the set of possible values of a given type. This super set of
|
||||
`T` plus some ['nil_t]—where `nil_t` is some stateless POD—can be modeled in modern
|
||||
languages as a [*discriminated union] of T and nil_t. Discriminated unions are
|
||||
often called ['variants]. A variant has a ['current type], which in our case is either
|
||||
`T` or `nil_t`.
|
||||
Using the __BOOST_VARIANT__ library, this model can be implemented in terms of `boost::variant<T,nil_t>`.
|
||||
There is precedent for a discriminated union as a model for an optional value:
|
||||
the __HASKELL__ [*Maybe] built-in type constructor. Thus, a discriminated union
|
||||
`T+nil_t` serves as a conceptual foundation.
|
||||
Such an object is said to have ['indeterminate value]. If you subsequently
|
||||
assign a proper value to the object, all is fine; but if the program tries to
|
||||
read an indeterminate value, this is ['undefined behavior'], and since C++26
|
||||
this is ['erroneous behavior].
|
||||
In any case, the program is now likely to do something else than what the
|
||||
programmer intended. In case you have some object `i`, and you do not know if it
|
||||
has an indeterminate value, or a normal, intended, value, there is no way to
|
||||
check it, because the checking would require reading the value.
|
||||
|
||||
A `variant<T,nil_t>` follows naturally from the traditional idiom of extending
|
||||
the range of possible values adding an additional sentinel value with the
|
||||
special meaning of ['Nothing]. However, this additional ['Nothing] value is largely
|
||||
irrelevant for our purpose since our goal is to formalize the notion of
|
||||
uninitialized objects and, while a special extended value can be used to convey
|
||||
that meaning, it is not strictly necessary in order to do so.
|
||||
This is one of the primary problems that `optional` was intended to address: so
|
||||
that you may have a type that knows whether it has been assigned a proper value,
|
||||
and it can tell you that if requested.
|
||||
|
||||
The observation made in the last paragraph about the irrelevant nature of the
|
||||
additional `nil_t` with respect to [_purpose] of `optional<T>` suggests an
|
||||
alternative model: a ['container] that either has a value of `T` or nothing.
|
||||
In the case of type `int` the internal representation of such a class could be:
|
||||
|
||||
As of this writing I don't know of any precedent for a variable-size
|
||||
fixed-capacity (of 1) stack-based container model for optional values, yet I
|
||||
believe this is the consequence of the lack of practical implementations of
|
||||
such a container rather than an inherent shortcoming of the container model.
|
||||
class OptionalInt
|
||||
{
|
||||
bool _has_value = false;
|
||||
int _value;
|
||||
};
|
||||
|
||||
In any event, both the discriminated-union or the single-element container
|
||||
models serve as a conceptual ground for a class representing optional—i.e.
|
||||
possibly uninitialized—objects.
|
||||
For instance, these models show the ['exact] semantics required for a wrapper
|
||||
of optional values:
|
||||
In the general case, the internal representation is something equivalent to:
|
||||
|
||||
Discriminated-union:
|
||||
template <typename T>
|
||||
class Optional
|
||||
{
|
||||
bool _has_value = false;
|
||||
alignas(T) char _value [sizeof(T)];
|
||||
};
|
||||
|
||||
* [*deep-copy] semantics: copies of the variant implies copies of the value.
|
||||
* [*deep-relational] semantics: comparisons between variants matches both
|
||||
current types and values
|
||||
* If the variant's current type is `T`, it is modeling an ['initialized] optional.
|
||||
* If the variant's current type is not `T`, it is modeling an ['uninitialized]
|
||||
optional.
|
||||
* Testing if the variant's current type is `T` models testing if the optional
|
||||
is initialized
|
||||
* Trying to extract a `T` from a variant when its current type is not `T`, models
|
||||
the undefined behavior of trying to access the value of an uninitialized optional
|
||||
or:
|
||||
|
||||
Single-element container:
|
||||
template <typename T>
|
||||
class Optional
|
||||
{
|
||||
bool _has_value = false;
|
||||
union {
|
||||
T _value;
|
||||
DummyType _non_value;
|
||||
};
|
||||
};
|
||||
|
||||
* [*deep-copy] semantics: copies of the container implies copies of the value.
|
||||
* [*deep-relational] semantics: comparisons between containers compare container
|
||||
size and if match, contained value
|
||||
* If the container is not empty (contains an object of type `T`), it is modeling
|
||||
an ['initialized] optional.
|
||||
* If the container is empty, it is modeling an ['uninitialized] optional.
|
||||
* Testing if the container is empty models testing if the optional is
|
||||
initialized
|
||||
* Trying to extract a `T` from an empty container models the undefined behavior
|
||||
of trying to access the value of an uninitialized optional
|
||||
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
|
||||
only then, to also copy `_value`.
|
||||
|
||||
[endsect]
|
||||
This means that our type requires ['deep copy] semantics.
|
||||
|
||||
[section The semantics]
|
||||
|
||||
Objects of type `optional<T>` are intended to be used in places where objects of
|
||||
type `T` would but which might be uninitialized. Hence, `optional<T>`'s purpose is
|
||||
to formalize the additional possibly uninitialized state.
|
||||
From the perspective of this role, `optional<T>` can have the same operational
|
||||
semantics of `T` plus the additional semantics corresponding to this special
|
||||
state.
|
||||
As such, `optional<T>` could be thought of as a ['supertype] of `T`. Of course, we
|
||||
can't do that in C++, so we need to compose the desired semantics using a
|
||||
different mechanism.
|
||||
Doing it the other way around, that is, making `optional<T>` a ['subtype] of `T`
|
||||
is not only conceptually wrong but also impractical: it is not allowed to
|
||||
derive from a non-class type, such as a built-in type.
|
||||
|
||||
We can draw from the purpose of `optional<T>` the required basic semantics:
|
||||
|
||||
* [*Default Construction:] To introduce a formally uninitialized wrapped
|
||||
object.
|
||||
* [*Direct Value Construction via copy:] To introduce a formally initialized
|
||||
wrapped object whose value is obtained as a copy of some object.
|
||||
* [*Deep Copy Construction:] To obtain a new yet equivalent wrapped object.
|
||||
* [*Direct Value Assignment (upon initialized):] To assign a value to the
|
||||
wrapped object.
|
||||
* [*Direct Value Assignment (upon uninitialized):] To initialize the wrapped
|
||||
object with a value obtained as a copy of some object.
|
||||
* [*Assignment (upon initialized):] To assign to the wrapped object the value
|
||||
of another wrapped object.
|
||||
* [*Assignment (upon uninitialized):] To initialize the wrapped object with
|
||||
value of another wrapped object.
|
||||
* [*Deep Relational Operations (when supported by the type T):] To compare
|
||||
wrapped object values taking into account the presence of uninitialized states.
|
||||
* [*Value access:] To unwrap the wrapped object.
|
||||
* [*Initialization state query:] To determine if the object is formally
|
||||
initialized or not.
|
||||
* [*Swap:] To exchange wrapped objects. (with whatever exception safety
|
||||
guarantees are provided by `T`'s swap).
|
||||
* [*De-initialization:] To release the wrapped object (if any) and leave the
|
||||
wrapper in the uninitialized state.
|
||||
|
||||
Additional operations are useful, such as converting constructors and
|
||||
converting assignments, in-place construction and assignment, and safe
|
||||
value access via a pointer to the wrapped object or null.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section The Interface]
|
||||
|
||||
Since the purpose of optional is to allow us to use objects with a formal
|
||||
uninitialized additional state, the interface could try to follow the
|
||||
interface of the underlying `T` type as much as possible. In order to choose
|
||||
the proper degree of adoption of the native `T` interface, the following must
|
||||
be noted: Even if all the operations supported by an instance of type `T` are
|
||||
defined for the entire range of values for such a type, an `optional<T>`
|
||||
extends such a set of values with a new value for which most
|
||||
(otherwise valid) operations are not defined in terms of `T`.
|
||||
|
||||
Furthermore, since `optional<T>` itself is merely a `T` wrapper (modeling a `T`
|
||||
supertype), any attempt to define such operations upon uninitialized optionals
|
||||
will be totally artificial w.r.t. `T`.
|
||||
|
||||
This library chooses an interface which follows from `T`'s interface only for
|
||||
those operations which are well defined (w.r.t the type `T`) even if any of the
|
||||
operands are uninitialized. These operations include: construction,
|
||||
copy-construction, assignment, swap and relational operations.
|
||||
|
||||
For the value access operations, which are undefined (w.r.t the type `T`) when
|
||||
the operand is uninitialized, a different interface is chosen (which will be
|
||||
explained next).
|
||||
|
||||
Also, the presence of the possibly uninitialized state requires additional
|
||||
operations not provided by `T` itself which are supported by a special interface.
|
||||
|
||||
[heading Lexically-hinted Value Access in the presence of possibly
|
||||
uninitialized optional objects: The operators * and ->]
|
||||
|
||||
A relevant feature of a pointer is that it can have a [*null pointer value].
|
||||
This is a ['special] value which is used to indicate that the pointer is not
|
||||
referring to any object at all. In other words, null pointer values convey
|
||||
the notion of nonexistent objects.
|
||||
|
||||
This meaning of the null pointer value allowed pointers to became a ['de
|
||||
facto] standard for handling optional objects because all you have to do
|
||||
to refer to a value which you don't really have is to use a null pointer
|
||||
value of the appropriate type. Pointers have been used for decades—from
|
||||
the days of C APIs to modern C++ libraries—to ['refer] to optional (that is,
|
||||
possibly nonexistent) objects; particularly as optional arguments to a
|
||||
function, but also quite often as optional data members.
|
||||
|
||||
The possible presence of a null pointer value makes the operations that
|
||||
access the pointee's value possibly undefined, therefore, expressions which
|
||||
use dereference and access operators, such as: `( *p = 2 )` and `( p->foo() )`,
|
||||
implicitly convey the notion of optionality, and this information is tied to
|
||||
the ['syntax] of the expressions. That is, the presence of operators `*` and `->`
|
||||
tell by themselves —without any additional context— that the expression will
|
||||
be undefined unless the implied pointee actually exist.
|
||||
|
||||
Such a ['de facto] idiom for referring to optional objects can be formalized
|
||||
in the form of a concept: the __OPTIONAL_POINTEE__ concept.
|
||||
This concept captures the syntactic usage of operators `*`, `->` and
|
||||
contextual conversion to `bool` to convey the notion of optionality.
|
||||
|
||||
However, pointers are good to [_refer] to optional objects, but not particularly
|
||||
good to handle the optional objects in all other respects, such as initializing
|
||||
or moving/copying them. The problem resides in the shallow-copy of pointer
|
||||
semantics: if you need to effectively move or copy the object, pointers alone
|
||||
are not enough. The problem is that copies of pointers do not imply copies of
|
||||
pointees. For example, as was discussed in the motivation, pointers alone
|
||||
cannot be used to return optional objects from a function because the object
|
||||
must move outside from the function and into the caller's context.
|
||||
|
||||
A solution to the shallow-copy problem that is often used is to resort to
|
||||
dynamic allocation and use a smart pointer to automatically handle the details
|
||||
of this. For example, if a function is to optionally return an object `X`, it can
|
||||
use `shared_ptr<X>` as the return value. However, this requires dynamic allocation
|
||||
of `X`. If `X` is a built-in or small POD, this technique is very poor in terms of
|
||||
required resources. Optional objects are essentially values so it is very
|
||||
convenient to be able to use automatic storage and deep-copy semantics to
|
||||
manipulate optional values just as we do with ordinary values. Pointers do
|
||||
not have this semantics, so are inappropriate for the initialization and
|
||||
transport of optional values, yet are quite convenient for handling the access
|
||||
to the possible undefined value because of the idiomatic aid present in the
|
||||
__OPTIONAL_POINTEE__ concept incarnated by pointers.
|
||||
|
||||
|
||||
[heading Optional<T> as a model of OptionalPointee]
|
||||
|
||||
For value access operations `optional<>` uses operators `*` and `->` to
|
||||
lexically warn about the possibly uninitialized state appealing to the
|
||||
familiar pointer semantics w.r.t. to null pointers.
|
||||
|
||||
[caution
|
||||
However, it is particularly important to note that `optional<>` objects
|
||||
are not pointers. [_`optional<>` is not, and does not model, a pointer].
|
||||
[note
|
||||
This is a C++ equivalent of a
|
||||
[@https://hackage.haskell.org/package/base-4.20.0.1/docs/Data-Maybe.html Maybe]
|
||||
monad in [@http://www.haskell.org/ Haskell].
|
||||
]
|
||||
|
||||
For instance, `optional<>` does not have shallow-copy so does not alias:
|
||||
two different optionals never refer to the ['same] value unless `T` itself is
|
||||
a reference (but may have ['equivalent] values).
|
||||
The difference between an `optional<T>` and a pointer must be kept in mind,
|
||||
particularly because the semantics of relational operators are different:
|
||||
since `optional<T>` is a value-wrapper, relational operators are deep: they
|
||||
compare optional values; but relational operators for pointers are shallow:
|
||||
they do not compare pointee values.
|
||||
As a result, you might be able to replace `optional<T>` by `T*` on some
|
||||
situations but not always. Specifically, on generic code written for both,
|
||||
you cannot use relational operators directly, and must use the template
|
||||
functions __FUNCTION_EQUAL_POINTEES__ and __FUNCTION_LESS_POINTEES__ instead.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:iface Interface Design]
|
||||
One part of the interface is for modifying and setting the initial state of
|
||||
the object. It has to be able to say that
|
||||
|
||||
* we want to store a specific value of type `T`,
|
||||
* we want to store no value.
|
||||
|
||||
The default constructor stores no value. Other than that, we require that
|
||||
the assignment and construction from a `T` reflects the former, while assignment
|
||||
and construction of a special ['tag] value `none` reflect the latter need.
|
||||
|
||||
optional<int> o1; // contains no value
|
||||
optional<int> o2 = 2; // contains value 2
|
||||
optional<int> o3 = none; // contains no value
|
||||
|
||||
o1 = 1; // assign value 1
|
||||
o2 = none; // assign a no-value
|
||||
o3 = {}; // assign a no-value
|
||||
|
||||
[heading Inspecting the State]
|
||||
|
||||
Inspecting the state of an optional object requires two steps:
|
||||
|
||||
* check if we have the value or not,
|
||||
* if so, read the stored value.
|
||||
|
||||
This 'procedure' is characteristic of inspecting pointers in C++, therefore the
|
||||
pointer-like syntax was chosen to represent this.
|
||||
|
||||
void inspect (optional<string> os)
|
||||
{
|
||||
if (os) { // contextual conversion to `bool`
|
||||
read_string(*os); // `operator*` to access the stored value
|
||||
read_int(os->size()); // `operator->` as shortcut for accessing members
|
||||
}
|
||||
}
|
||||
|
||||
Also, similarly to pointers, if you access the value when it is not there,
|
||||
you trigger __UB__.
|
||||
This library detects and reports it via
|
||||
[@../../../assert/assert.html `BOOST_ASSERT()`]. This common property of
|
||||
pointers and `optional<>` has been formalized into a concept __OPTIONAL_POINTEE__.
|
||||
|
||||
However, there is also the counter-intuitive part. All pointers embed ['shallow-copy]
|
||||
semantics: when you copy a pointer, the pointed-to object stays at the same location
|
||||
and you can access it via either of the pointers. This is unlike optional objects
|
||||
where the represented value is copied along.
|
||||
|
||||
[caution
|
||||
Optional objects are not pointers.
|
||||
]
|
||||
|
||||
There is a similar difference in relational operations: they compare deeply for
|
||||
`optional<>`, while they are shallow for pointers.
|
||||
|
||||
[note
|
||||
When you need a deep relational operations that work uniformly for `optional<>`
|
||||
and pointers in generic contexts, use functions
|
||||
[@../../../utility/OptionalPointee.html#equal `equal_pointees()`] and
|
||||
[@../../../utility/OptionalPointee.html#less `less_pointees()`].
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
|
||||
[section Convenience Conversions and Deductions]
|
||||
|
||||
Unlike `std::optional`, `boost::optional` does not offer a number of
|
||||
"convenience" converting constructors, mixed relational operations and
|
||||
deductions for class template parameters.
|
||||
|
||||
std::optional oi = 1; // OK
|
||||
|
||||
std:string_view sv = "hi";
|
||||
std::optional<std::string> os = sv; // OK
|
||||
os == sv; // OK
|
||||
|
||||
std::optional<std::string> osv;
|
||||
std::optional<std::string> os2 = osv; // OK
|
||||
os2 == osv; // OK
|
||||
|
||||
They are practical, and sometimes stem from the argument for consistency:
|
||||
if `(optT && *optT == u)` works then `(optT == u)` should also work.
|
||||
|
||||
However, these intelligent convenience functions sometimes produce results
|
||||
that are counter to the programmer intentions and produce silent bugs.
|
||||
|
||||
Consider a more complicated example:
|
||||
|
||||
Threshold th = /*...*/;
|
||||
std::optional o = th;
|
||||
assert (o);
|
||||
|
||||
In this code, can we expect that thus initialized `optional` contains a value?
|
||||
The answer is: it depends on the type of `Threshold`. It can be defined as:
|
||||
|
||||
using Threshold = std::optional<int>;
|
||||
|
||||
And then the assertion will fire. This is because in this case the intelligence
|
||||
decides that since we already have an optional, the additional wrapping into
|
||||
a yet another optional is unnecessary.
|
||||
|
||||
If we explicitly specify the template type, the situation doesn't get less
|
||||
complicated.
|
||||
|
||||
Threshold th;
|
||||
std::optional<Threshold> o = th;
|
||||
assert(o);
|
||||
|
||||
Can this assertion fire? Now we have two competing constructors:
|
||||
|
||||
template <typename U>
|
||||
optional(U const&);
|
||||
|
||||
template <typename U>
|
||||
optional(optional<U> const&);
|
||||
|
||||
Which one will get chosen? Actually, we are lucky, and it is going to be the
|
||||
first one due to concept tricks. But let's try a different example:
|
||||
|
||||
Threshold th;
|
||||
std::optional<Threshold> o = th;
|
||||
assert(o);
|
||||
assert(o == th);
|
||||
|
||||
Here, the first assertion passes, but the second one fires. This is because
|
||||
there are two competing overloads of the comparison operator:
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(optional<T> const&, U const&);
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(optional<T> const&, optional<U> const&);
|
||||
|
||||
And this time there is no concept trickery, so the second overload is chosen,
|
||||
and gives different results: we are comparing an optional object `th`, which does
|
||||
not contain a value, with an optional object `o` which does contain a value.
|
||||
|
||||
This problem -- that the operations compile, but have runtime behavior counter
|
||||
to programmer's intuition -- gains new significance with the introduction of
|
||||
concepts to C++.
|
||||
|
||||
static_assert(std::equality_comparable_with<std::optional<Threshold>, Threshold>);
|
||||
|
||||
Concepts have both syntactic constraints and semantic constraints. Syntactic
|
||||
constraints are statically checked by the compiler. For semantic constraints,
|
||||
functions that use the concept trust the programmer that these constraints are
|
||||
met, and if not, this is __UB__.
|
||||
|
||||
These are problems with `std::optional`. `boost::optional` doesn't have these
|
||||
problems, because it does not offer the said convenience operations.
|
||||
|
||||
The design principle for `boost::optional` is not to offer functionality that
|
||||
nicely deduces the programmer intentions in 95% of the cases, and in the remaining
|
||||
5% renders effects counter to programmer expectations.
|
||||
|
||||
Instead, this library recommends using a more verbose syntax that works in 100%
|
||||
of the cases:
|
||||
|
||||
Threshold th;
|
||||
auto o = boost::make_potional(th); // *always* add a new layer of optionality
|
||||
|
||||
return boost::equal_pointees(o, th); // *always* unpack optionals for comparison
|
||||
return o && *o == th; // *always* treat the right-hand side argument as value
|
||||
|
||||
[endsect]
|
||||
@@ -1,45 +0,0 @@
|
||||
[section Monadic interface]
|
||||
|
||||
The monadic interface of `optional` allows the application of functions
|
||||
to optional values without resorting to the usage of explicit `if`-statements.
|
||||
|
||||
Function `map` takes a function mapping type `T` onto type `U` and maps an `optional<T>`
|
||||
onto an `optional<U>` using the provided function.
|
||||
|
||||
int length(const string& s){ return s.size(); };
|
||||
|
||||
optional<string> null{}, thin{""}, word{"word"};
|
||||
assert (null.map(length) == none);
|
||||
assert (thin.map(length) == 0);
|
||||
assert (word.map(length) == 4);
|
||||
|
||||
Function `flat_map` is similar, but it requires the function to return an
|
||||
`optional<V>` for some type `V`. This `optional<V>` becomes the return type of
|
||||
`flat_map`.
|
||||
|
||||
optional<char> first_char(const string& s) {
|
||||
if (s.empty()) return none;
|
||||
else return s[0];
|
||||
};
|
||||
|
||||
optional<string> null{}, thin{""}, word{"word"};
|
||||
assert (null.flat_map(first_char) == none);
|
||||
assert (thin.flat_map(first_char) == none);
|
||||
assert (word.flat_map(first_char) == 'w');
|
||||
|
||||
These functions can be combined in one expression reflecting a chain of computations:
|
||||
|
||||
auto get_contents(path p) -> optional<string>;
|
||||
auto trim(string) -> string;
|
||||
auto length(string) -> int;
|
||||
|
||||
auto trimmed_size_of(optional<path> p) -> int
|
||||
{
|
||||
return p.flat_map(get_contents)
|
||||
.map(trim)
|
||||
.map(length)
|
||||
.value_or(0);
|
||||
}
|
||||
|
||||
|
||||
[endsect]
|
||||
@@ -23,7 +23,12 @@ will nonetheless refer to the same object.
|
||||
* Value-access will actually provide access to the referenced object
|
||||
rather than the reference itself.
|
||||
|
||||
[caution 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 boost_optional.dependencies_and_portability.optional_reference_binding Dependencies and Portability section].]
|
||||
[caution
|
||||
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].
|
||||
]
|
||||
|
||||
[heading Rvalue references]
|
||||
|
||||
@@ -34,6 +39,8 @@ 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
|
||||
@@ -45,7 +52,7 @@ the first time) to the object. Clearly, there is no other choice.
|
||||
optional<int&> orb(x) ;
|
||||
ora = orb ; // now 'ora' is bound to 'x' through 'rx'
|
||||
*ora = 2 ; // Changes value of 'x' through 'ora'
|
||||
assert(x==2);
|
||||
assert(x==2);
|
||||
|
||||
If you assign to a bare C++ reference, the assignment is forwarded to the
|
||||
referenced object; its value changes but the reference is never rebound.
|
||||
@@ -71,8 +78,8 @@ bare C++ references.
|
||||
optional<int&> orb(rb) ;
|
||||
ora = orb ; // 'ora' is rebound to 'b'
|
||||
*ora = 3 ; // Changes value of 'b' (not 'a')
|
||||
assert(a==1);
|
||||
assert(b==3);
|
||||
assert(a==1);
|
||||
assert(b==3);
|
||||
|
||||
[heading Rationale]
|
||||
|
||||
|
||||
@@ -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
|
||||
interfaces usually provide an operation to initialize or assign the
|
||||
@@ -136,4 +136,6 @@ In-place factories can be used generically by the wrapper and user as follows:
|
||||
|
||||
The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYPED_IN_PLACE_FACTORY_HPP__
|
||||
|
||||
[endsect]
|
||||
[caution The support for in-place factories is deprecated. Use constructor taking `in_place_init` tag and function `.emplace()` instead.]
|
||||
|
||||
[endsect:in_place_factories]
|
||||
|
||||
@@ -7,8 +7,8 @@ The very minimum requirement of `optional<T>` is that `T` is a complete type and
|
||||
assert(o == none); // check if initialized
|
||||
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.tutorial.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;
|
||||
o.emplace("T", "ctor", "params");
|
||||
@@ -17,13 +17,13 @@ If `T` is __MOVE_CONSTRUCTIBLE__, `optional<T>` is also __MOVE_CONSTRUCTIBLE__ a
|
||||
|
||||
optional<T> o = make_T();
|
||||
optional<T> p = optional<T>();
|
||||
|
||||
|
||||
If `T` is __COPY_CONSTRUCTIBLE__, `optional<T>` is also __COPY_CONSTRUCTIBLE__ and can be easily initialized from an lvalue of type `T`:
|
||||
|
||||
T v = make_T();
|
||||
optional<T> o = v;
|
||||
optional<T> p = o;
|
||||
|
||||
|
||||
If `T` is not `MoveAssignable`, it is still possible to reset the value of `optional<T>` using function `emplace()`:
|
||||
|
||||
optional<const T> o = make_T();
|
||||
|
||||
+14
-3
@@ -2,7 +2,7 @@
|
||||
Boost.Optional
|
||||
|
||||
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.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -15,14 +15,25 @@
|
||||
```
|
||||
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 */);
|
||||
|
||||
} // 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`.
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
namespace boost {
|
||||
|
||||
class in_place_init_t { /* see below */ } ; ``[link reference_in_place_init __GO_TO__]``
|
||||
const in_place_init_t in_place_init ( /* see below */ ) ;
|
||||
inline constexpr in_place_init_t in_place_init ( /* see below */ ) ;
|
||||
|
||||
class in_place_init_if_t { /*see below*/ } ; ``[link reference_in_place_init_if __GO_TO__]``
|
||||
const in_place_init_if_t in_place_init_if ( /*see below*/ ) ;
|
||||
inline constexpr in_place_init_if_t in_place_init_if ( /*see below*/ ) ;
|
||||
|
||||
template <class T>
|
||||
class optional ; ``[link reference_operator_template __GO_TO__]``
|
||||
@@ -95,10 +95,10 @@
|
||||
namespace boost {
|
||||
|
||||
class in_place_init_t { /* see below */ } ;
|
||||
const in_place_init_t in_place_init ( /* see below */ ) ;
|
||||
inline constexpr in_place_init_t in_place_init ( /* see below */ ) ;
|
||||
|
||||
class in_place_init_if_t { /*see below*/ } ;
|
||||
const in_place_init_if_t in_place_init_if ( /*see below*/ ) ;
|
||||
inline constexpr in_place_init_if_t in_place_init_if ( /*see below*/ ) ;
|
||||
|
||||
}
|
||||
|
||||
@@ -123,33 +123,33 @@ They are empty, trivially copyable classes with disabled default constructor.
|
||||
typedef T * pointer_type ;
|
||||
typedef T const* pointer_const_type ;
|
||||
|
||||
optional () noexcept ; ``[link reference_optional_constructor __GO_TO__]``
|
||||
constexpr optional () noexcept ; ``[link reference_optional_constructor __GO_TO__]``
|
||||
|
||||
optional ( none_t ) noexcept ; ``[link reference_optional_constructor_none_t __GO_TO__]``
|
||||
constexpr optional ( none_t ) noexcept ; ``[link reference_optional_constructor_none_t __GO_TO__]``
|
||||
|
||||
optional ( T const& v ) ; ``[link reference_optional_constructor_value __GO_TO__]``
|
||||
constexpr optional ( T const& v ) ; ``[link reference_optional_constructor_value __GO_TO__]``
|
||||
|
||||
optional ( T&& v ) ; ``[link reference_optional_constructor_move_value __GO_TO__]``
|
||||
constexpr optional ( T&& v ) ; ``[link reference_optional_constructor_move_value __GO_TO__]``
|
||||
|
||||
optional ( bool condition, T const& v ) ; ``[link reference_optional_constructor_bool_value __GO_TO__]``
|
||||
constexpr optional ( bool condition, T const& v ) ; ``[link reference_optional_constructor_bool_value __GO_TO__]``
|
||||
|
||||
optional ( optional const& rhs ) ; ``[link reference_optional_constructor_optional __GO_TO__]``
|
||||
constexpr optional ( optional const& rhs ) ; ``[link reference_optional_constructor_optional __GO_TO__]``
|
||||
|
||||
optional ( optional&& rhs ) noexcept(``['see below]``) ; ``[link reference_optional_move_constructor_optional __GO_TO__]``
|
||||
constexpr optional ( optional&& rhs ) noexcept(``['see below]``) ; ``[link reference_optional_move_constructor_optional __GO_TO__]``
|
||||
|
||||
template<class U> explicit optional ( optional<U> const& rhs ) ; ``[link reference_optional_constructor_other_optional __GO_TO__]``
|
||||
template<class U> constexpr explicit optional ( optional<U> const& rhs ) ; ``[link reference_optional_constructor_other_optional __GO_TO__]``
|
||||
|
||||
template<class U> explicit optional ( optional<U>&& rhs ) ; ``[link reference_optional_move_constructor_other_optional __GO_TO__]``
|
||||
template<class U> constexpr explicit optional ( optional<U>&& rhs ) ; ``[link reference_optional_move_constructor_other_optional __GO_TO__]``
|
||||
|
||||
template<class... Args> explicit optional ( in_place_init_t, Args&&... args ) ; ``[link reference_optional_in_place_init __GO_TO__]``
|
||||
template<class... Args> constexpr explicit optional ( in_place_init_t, Args&&... args ) ; ``[link reference_optional_in_place_init __GO_TO__]``
|
||||
|
||||
template<class... Args> explicit optional ( in_place_init_if_t, bool condition, Args&&... args ) ; ``[link reference_optional_in_place_init_if __GO_TO__]``
|
||||
template<class... Args> constexpr explicit optional ( in_place_init_if_t, bool condition, Args&&... args ) ; ``[link reference_optional_in_place_init_if __GO_TO__]``
|
||||
|
||||
template<class InPlaceFactory> explicit optional ( InPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]``
|
||||
|
||||
template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]``
|
||||
|
||||
optional& operator = ( none_t ) noexcept ; ``[link reference_optional_operator_equal_none_t __GO_TO__]``
|
||||
constexpr optional& operator = ( none_t ) noexcept ; ``[link reference_optional_operator_equal_none_t __GO_TO__]``
|
||||
|
||||
optional& operator = ( T const& v ) ; ``[link reference_optional_operator_equal_value __GO_TO__]``
|
||||
|
||||
@@ -169,44 +169,45 @@ They are empty, trivially copyable classes with disabled default constructor.
|
||||
|
||||
template<class TypedInPlaceFactory> optional& operator = ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_operator_equal_factory __GO_TO__]``
|
||||
|
||||
T const& get() const ; ``[link reference_optional_get __GO_TO__]``
|
||||
T& get() ; ``[link reference_optional_get __GO_TO__]``
|
||||
constexpr T const& get() const ; ``[link reference_optional_get __GO_TO__]``
|
||||
constexpr T& get() ; ``[link reference_optional_get __GO_TO__]``
|
||||
|
||||
T const* operator ->() const ; ``[link reference_optional_operator_arrow __GO_TO__]``
|
||||
T* operator ->() ; ``[link reference_optional_operator_arrow __GO_TO__]``
|
||||
constexpr T const* operator ->() const ; ``[link reference_optional_operator_arrow __GO_TO__]``
|
||||
constexpr T* operator ->() ; ``[link reference_optional_operator_arrow __GO_TO__]``
|
||||
|
||||
T const& operator *() const& ; ``[link reference_optional_operator_asterisk __GO_TO__]``
|
||||
T& operator *() & ; ``[link reference_optional_operator_asterisk __GO_TO__]``
|
||||
T&& operator *() && ; ``[link reference_optional_operator_asterisk_move __GO_TO__]``
|
||||
constexpr T const& operator *() const& ; ``[link reference_optional_operator_asterisk __GO_TO__]``
|
||||
constexpr T& operator *() & ; ``[link reference_optional_operator_asterisk __GO_TO__]``
|
||||
constexpr T&& operator *() && ; ``[link reference_optional_operator_asterisk_move __GO_TO__]``
|
||||
|
||||
T const& value() const& ; ``[link reference_optional_value __GO_TO__]``
|
||||
T& value() & ; ``[link reference_optional_value __GO_TO__]``
|
||||
T&& value() && ; ``[link reference_optional_value_move __GO_TO__]``
|
||||
constexpr T const& value() const& ; ``[link reference_optional_value __GO_TO__]``
|
||||
constexpr T& value() & ; ``[link reference_optional_value __GO_TO__]``
|
||||
constexpr T&& value() && ; ``[link reference_optional_value_move __GO_TO__]``
|
||||
|
||||
template<class U> T value_or( U && v ) const& ; ``[link reference_optional_value_or __GO_TO__]``
|
||||
template<class U> T value_or( U && v ) && ; ``[link reference_optional_value_or_move __GO_TO__]``
|
||||
template<class U> constexpr T value_or( U && v ) const& ; ``[link reference_optional_value_or __GO_TO__]``
|
||||
template<class U> constexpr T value_or( U && v ) && ; ``[link reference_optional_value_or_move __GO_TO__]``
|
||||
|
||||
template<class F> T value_or_eval( F f ) const& ; ``[link reference_optional_value_or_call __GO_TO__]``
|
||||
template<class F> T value_or_eval( F f ) && ; ``[link reference_optional_value_or_call_move __GO_TO__]``
|
||||
template<class F> constexpr T value_or_eval( F f ) const& ; ``[link reference_optional_value_or_call __GO_TO__]``
|
||||
template<class F> constexpr T value_or_eval( F f ) && ; ``[link reference_optional_value_or_call_move __GO_TO__]``
|
||||
|
||||
template<class F> auto map( F f ) const& -> ``['see below]``; ``[link reference_optional_map __GO_TO__]``
|
||||
template<class F> auto map( F f ) & -> ``['see below]``; ``[link reference_optional_map __GO_TO__]``
|
||||
template<class F> auto map( F f ) && -> ``['see below]``; ``[link reference_optional_map_move __GO_TO__]``
|
||||
template<class F> constexpr auto map( F f ) const& -> ``['see below]``; ``[link reference_optional_map __GO_TO__]``
|
||||
template<class F> constexpr auto map( F f ) & -> ``['see below]``; ``[link reference_optional_map __GO_TO__]``
|
||||
template<class F> constexpr auto map( F f ) && -> ``['see below]``; ``[link reference_optional_map_move __GO_TO__]``
|
||||
|
||||
template<class F> auto flat_map( F f ) const& -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]``
|
||||
template<class F> auto flat_map( F f ) & -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]``
|
||||
template<class F> auto flat_map( F f ) && -> ``['see below]``; ``[link reference_optional_flat_map_move __GO_TO__]``
|
||||
template<class F> constexpr auto flat_map( F f ) const& -> ``['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__]``
|
||||
|
||||
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__]``
|
||||
|
||||
bool has_value() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]``
|
||||
constexpr bool has_value() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]``
|
||||
|
||||
explicit operator bool() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]``
|
||||
constexpr explicit operator bool() const noexcept ; ``[link reference_optional_operator_bool __GO_TO__]``
|
||||
|
||||
bool operator!() const noexcept ; ``[link reference_optional_operator_not __GO_TO__]``
|
||||
|
||||
void reset() noexcept ; ``[link reference_optional_reset __GO_TO__]``
|
||||
constexpr void reset() noexcept ; ``[link reference_optional_reset __GO_TO__]``
|
||||
|
||||
// deprecated methods
|
||||
|
||||
@@ -214,7 +215,7 @@ They are empty, trivially copyable classes with disabled default constructor.
|
||||
void reset ( T const& ) ; ``[link reference_optional_reset_value __GO_TO__]``
|
||||
|
||||
// (deprecated)
|
||||
bool is_initialized() const ; ``[link reference_optional_is_initialized __GO_TO__]``
|
||||
constexpr bool is_initialized() const ; ``[link reference_optional_is_initialized __GO_TO__]``
|
||||
|
||||
// (deprecated)
|
||||
T const& get_value_or( T const& default ) const ; ``[link reference_optional_get_value_or_value __GO_TO__]``
|
||||
@@ -239,9 +240,9 @@ They are empty, trivially copyable classes with disabled default constructor.
|
||||
typedef T* pointer_type;
|
||||
typedef T* pointer_const_type; // no const propagation
|
||||
|
||||
optional () noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]``
|
||||
constexpr optional () noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]``
|
||||
|
||||
optional ( none_t ) noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]``
|
||||
constexpr optional ( none_t ) noexcept ; ``[link reference_optional_ref_default_ctor __GO_TO__]``
|
||||
|
||||
template<class R> optional(R&& r) noexcept ; ``[link reference_optional_ref_value_ctor __GO_TO__]``
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
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
|
||||
@@ -23,40 +24,40 @@ __SPACE__
|
||||
|
||||
[#reference_optional_constructor]
|
||||
|
||||
[: `optional<T>::optional() noexcept;`]
|
||||
[: `constexpr optional<T>::optional() noexcept;`]
|
||||
|
||||
* [*Effect:] Default-Constructs an `optional`.
|
||||
* [*Postconditions:] `*this` is [_uninitialized].
|
||||
* [*Notes:] T's default constructor [_is not] called.
|
||||
* [*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.
|
||||
* [*Example:]
|
||||
``
|
||||
optional<T> def ;
|
||||
assert ( !def ) ;
|
||||
optional<T> oN ;
|
||||
assert ( !oN ) ;
|
||||
``
|
||||
|
||||
__SPACE__
|
||||
|
||||
|
||||
[#reference_optional_constructor_none_t]
|
||||
[: `constexpr optional<T>::optional( none_t ) noexcept;`]
|
||||
|
||||
[: `optional<T>::optional( none_t ) noexcept;`]
|
||||
|
||||
* [*Effect:] Constructs an `optional` uninitialized.
|
||||
* [*Postconditions:] `*this` is [_uninitialized].
|
||||
* [*Notes:] `T`'s default constructor [_is not] called. The expression
|
||||
* [*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
|
||||
`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__
|
||||
|
||||
[#reference_optional_constructor_value]
|
||||
|
||||
[: `optional<T>::optional( T const& v )`]
|
||||
[: `constexpr optional<T>::optional( T const& v )`]
|
||||
|
||||
* [*Requires:] `is_copy_constructible<T>::value` is `true`.
|
||||
* [*Effect:] Directly-Constructs an `optional`.
|
||||
@@ -78,7 +79,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_constructor_move_value]
|
||||
|
||||
[: `optional<T>::optional( T&& v )`]
|
||||
[: `constexpr optional<T>::optional( T&& v )`]
|
||||
|
||||
* [*Requires:] `is_move_constructible<T>::value` is `true`.
|
||||
* [*Effect:] Directly-Move-Constructs an `optional`.
|
||||
@@ -99,7 +100,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_constructor_bool_value]
|
||||
|
||||
[: `optional<T>::optional( bool condition, T const& v ) ;` ]
|
||||
[: `constexpr optional<T>::optional( bool condition, T const& v ) ;` ]
|
||||
|
||||
* If condition is true, same as:
|
||||
|
||||
@@ -114,7 +115,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_constructor_optional]
|
||||
|
||||
[: `optional<T>::optional( optional const& rhs );`]
|
||||
[: `constexpr optional<T>::optional( optional const& rhs );`]
|
||||
|
||||
* [*Requires:] `is_copy_constructible<T>::value` is `true`.
|
||||
* [*Effect:] Copy-Constructs an `optional`.
|
||||
@@ -144,7 +145,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_move_constructor_optional]
|
||||
|
||||
[: `optional<T>::optional( optional&& rhs ) noexcept(`['see below]`);`]
|
||||
[: `constexpr optional<T>::optional( optional&& rhs ) noexcept(`['see below]`);`]
|
||||
|
||||
* [*Requires:] `is_move_constructible<T>::value` is `true`.
|
||||
* [*Effect:] Move-constructs an `optional`.
|
||||
@@ -178,7 +179,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_constructor_other_optional]
|
||||
|
||||
[: `template<U> explicit optional<T>::optional( optional<U> const& rhs );`]
|
||||
[: `template<U> constexpr explicit optional<T>::optional( optional<U> const& rhs );`]
|
||||
|
||||
* [*Effect:] Copy-Constructs an `optional`.
|
||||
* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its
|
||||
@@ -202,7 +203,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_move_constructor_other_optional]
|
||||
|
||||
[: `template<U> explicit optional<T>::optional( optional<U>&& rhs );`]
|
||||
[: `template<U> constexpr explicit optional<T>::optional( optional<U>&& rhs );`]
|
||||
|
||||
* [*Effect:] Move-constructs an `optional`.
|
||||
* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its
|
||||
@@ -226,14 +227,14 @@ __SPACE__
|
||||
|
||||
[#reference_optional_in_place_init]
|
||||
|
||||
[: `template<class... Args> explicit optional<T>::optional( in_place_init_t, Args&&... ars );`]
|
||||
[: `template<class... Args> constexpr explicit optional<T>::optional( in_place_init_t, Args&&... ars );`]
|
||||
|
||||
* [*Requires:] `is_constructible_v<T, Args&&...>` is `true`.
|
||||
* [*Effect:] Initializes the contained value as if direct-non-list-initializing an object of type `T` with the
|
||||
arguments `std::forward<Args>(args)...`.
|
||||
* [*Postconditions:] `*this` is initialized.
|
||||
* [*Throws:] Any exception thrown by the selected constructor of `T`.
|
||||
* [*Notes: ] `T` need not be __MOVE_CONSTRUCTIBLE__. On compilers that do not support variadic templates or rvalue references, this constuctor is available in limited functionality. For details [link optional_emplace_workaround see here].
|
||||
* [*Notes: ] `T` need not be __MOVE_CONSTRUCTIBLE__.
|
||||
|
||||
* [*Example:]
|
||||
``
|
||||
@@ -251,13 +252,13 @@ __SPACE__
|
||||
|
||||
[#reference_optional_in_place_init_if]
|
||||
|
||||
[: `template<class... Args> explicit optional<T>::optional( in_place_init_if_t, bool condition, Args&&... ars );`]
|
||||
[: `template<class... Args> constexpr explicit optional<T>::optional( in_place_init_if_t, bool condition, Args&&... ars );`]
|
||||
|
||||
* [*Requires:] `is_constructible_v<T, Args&&...>` is `true`.
|
||||
* [*Effect:] If `condition` is `true`, initializes the contained value as if direct-non-list-initializing an object of type `T` with the arguments `std::forward<Args>(args)...`.
|
||||
* [*Postconditions:] `bool(*this) == condition`.
|
||||
* [*Throws:] Any exception thrown by the selected constructor of `T`.
|
||||
* [*Notes: ] `T` need not be __MOVE_CONSTRUCTIBLE__. On compilers that do not support variadic templates or rvalue references, this constuctor is available in limited functionality. For details [link optional_emplace_workaround see here].
|
||||
* [*Notes: ] `T` need not be __MOVE_CONSTRUCTIBLE__.
|
||||
|
||||
* [*Example:]
|
||||
``
|
||||
@@ -281,7 +282,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.tutorial.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
|
||||
the `T` constructor used by the factory; in that case, this constructor has
|
||||
no effect.
|
||||
@@ -302,7 +303,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_operator_equal_none_t]
|
||||
|
||||
[: `optional& optional<T>::operator= ( none_t ) noexcept;`]
|
||||
[: `constexpr optional& optional<T>::operator= ( none_t ) noexcept;`]
|
||||
|
||||
* [*Effect:] If `*this` is initialized destroys its contained value.
|
||||
* [*Postconditions: ] `*this` is uninitialized.
|
||||
@@ -502,7 +503,7 @@ __SPACE__
|
||||
* [*Postconditions: ] `*this` is [_initialized].
|
||||
* [*Throws:] Whatever the selected `T`'s constructor throws.
|
||||
* [*Exception Safety:] If an exception is thrown during the initialization of `T`, `*this` is ['uninitialized].
|
||||
* [*Notes:] `T` need not be __MOVE_CONSTRUCTIBLE__ or `MoveAssignable`. On compilers that do not support variadic templates or rvalue references, this function is available in limited functionality. For details [link optional_emplace_workaround see here].
|
||||
* [*Notes:] `T` need not be __MOVE_CONSTRUCTIBLE__ or `MoveAssignable`.
|
||||
* [*Example:]
|
||||
``
|
||||
T v;
|
||||
@@ -524,7 +525,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.tutorial.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
|
||||
the `T` constructor used by the factory; in that case, the `optional` object
|
||||
will be reset to be ['uninitialized].
|
||||
@@ -540,15 +541,15 @@ __SPACE__
|
||||
|
||||
[#reference_optional_reset]
|
||||
|
||||
[: `void optional<T>::reset() noexcept ;`]
|
||||
[: `constexpr void optional<T>::reset() noexcept ;`]
|
||||
* [*Effects:] Same as `operator=( none_t );`
|
||||
|
||||
__SPACE__
|
||||
|
||||
[#reference_optional_get]
|
||||
|
||||
[: `T const& optional<T>::get() const ;`]
|
||||
[: `T& optional<T>::get() ;`]
|
||||
[: `constexpr T const& optional<T>::get() const ;`]
|
||||
[: `constexpr T& optional<T>::get() ;`]
|
||||
|
||||
[: `inline T const& get ( optional<T> const& ) ;`]
|
||||
[: `inline T& get ( optional<T> &) ;`]
|
||||
@@ -563,8 +564,8 @@ __SPACE__
|
||||
|
||||
[#reference_optional_operator_asterisk]
|
||||
|
||||
[: `T const& optional<T>::operator*() const& ;`]
|
||||
[: `T& optional<T>::operator*() &;`]
|
||||
[: `constexpr T const& optional<T>::operator*() const& ;`]
|
||||
[: `constexpr T& optional<T>::operator*() &;`]
|
||||
|
||||
* [*Requires:] `*this` is initialized
|
||||
* [*Returns:] A reference to the contained value
|
||||
@@ -585,7 +586,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_operator_asterisk_move]
|
||||
|
||||
[: `T&& optional<T>::operator*() &&;`]
|
||||
[: `constexpr T&& optional<T>::operator*() &&;`]
|
||||
|
||||
* [*Requires:] `*this` contains a value.
|
||||
* [*Effects:] Equivalent to `return std::move(*val);`.
|
||||
@@ -596,8 +597,8 @@ __SPACE__
|
||||
|
||||
[#reference_optional_value]
|
||||
|
||||
[: `T const& optional<T>::value() const& ;`]
|
||||
[: `T& optional<T>::value() & ;`]
|
||||
[: `constexpr T const& optional<T>::value() const& ;`]
|
||||
[: `constexpr T& optional<T>::value() & ;`]
|
||||
|
||||
* [*Effects:] Equivalent to `return bool(*this) ? *val : throw bad_optional_access();`.
|
||||
* [*Notes:] On compilers that do not support ref-qualifiers on member functions these two overloads are replaced with the classical two: a `const` and non-`const` member functions.
|
||||
@@ -620,7 +621,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_value_move]
|
||||
|
||||
[: `T&& optional<T>::value() && ;`]
|
||||
[: `constexpr T&& optional<T>::value() && ;`]
|
||||
|
||||
* [*Effects:] Equivalent to `return bool(*this) ? std::move(*val) : throw bad_optional_access();`.
|
||||
* [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is not present.
|
||||
@@ -630,17 +631,25 @@ __SPACE__
|
||||
|
||||
[#reference_optional_value_or]
|
||||
|
||||
[: `template<class U> T optional<T>::value_or(U && v) const& ;`]
|
||||
[: `template<class U = T> constexpr T optional<T>::value_or(U && v) const& ;`]
|
||||
|
||||
* [*Effects:] Equivalent to `if (*this) return **this; else return std::forward<U>(v);`.
|
||||
* [*Remarks:] If `T` is not __COPY_CONSTRUCTIBLE__ or `U &&` is not convertible to `T`, the program is ill-formed.
|
||||
* [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is replaced with the `const`-qualified member function. On compilers without rvalue reference support the type of `v` becomes `U const&`.
|
||||
* [*Example:]
|
||||
``
|
||||
optional<int> oN, o1(1);
|
||||
|
||||
assert (o1.value_or(9) == 1);
|
||||
assert (oN.value_or(9) == 9);
|
||||
assert (oN.value_or({}) == 0);
|
||||
``
|
||||
|
||||
__SPACE__
|
||||
|
||||
[#reference_optional_value_or_move]
|
||||
|
||||
[: `template<class U> T optional<T>::value_or(U && v) && ;`]
|
||||
[: `template<class U> constexpr T optional<T>::value_or(U && v) && ;`]
|
||||
|
||||
* [*Effects:] Equivalent to `if (*this) return std::move(**this); else return std::forward<U>(v);`.
|
||||
* [*Remarks:] If `T` is not __MOVE_CONSTRUCTIBLE__ or `U &&` is not convertible to `T`, the program is ill-formed.
|
||||
@@ -650,7 +659,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_value_or_call]
|
||||
|
||||
[: `template<class F> T optional<T>::value_or_eval(F f) const& ;`]
|
||||
[: `template<class F> constexpr T optional<T>::value_or_eval(F f) const& ;`]
|
||||
|
||||
* [*Requires:] `T` is __COPY_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`.
|
||||
* [*Effects:] `if (*this) return **this; else return f();`.
|
||||
@@ -677,7 +686,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_value_or_call_move]
|
||||
|
||||
[: `template<class F> T optional<T>::value_or_eval(F f) && ;`]
|
||||
[: `template<class F> constexpr T optional<T>::value_or_eval(F f) && ;`]
|
||||
|
||||
* [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`.
|
||||
* [*Effects:] `if (*this) return std::move(**this); else return f();`.
|
||||
@@ -687,8 +696,8 @@ __SPACE__
|
||||
|
||||
[#reference_optional_map]
|
||||
|
||||
[: `template<class F> auto optional<T>::map(F f) const& -> `['see below]` ;`]
|
||||
[: `template<class F> auto optional<T>::map(F f) & -> `['see below]` ;`]
|
||||
[: `template<class F> constexpr auto optional<T>::map(F f) const& -> `['see below]` ;`]
|
||||
[: `template<class F> constexpr auto optional<T>::map(F f) & -> `['see below]` ;`]
|
||||
|
||||
* [*Effects:] `if (*this) return f(**this); else return none;`
|
||||
* [*Notes:] The return type of these overloads is `optional<decltype(f(**this))>`. On compilers that do not support ref-qualifiers on member functions, these two (as well as the next one) overloads are replaced with good old const and non-const overloads.
|
||||
@@ -706,7 +715,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_map_move]
|
||||
|
||||
[: `template<class F> auto optional<T>::map(F f) && -> `['see below]` ;`]
|
||||
[: `template<class F> constexpr auto optional<T>::map(F f) && -> `['see below]` ;`]
|
||||
|
||||
* [*Effects:] `if (*this) return f(std::move(**this)); else return none;`
|
||||
* [*Notes:] The return type of this overload is `optional<decltype(f(istd::move(**this)))>`.
|
||||
@@ -715,8 +724,8 @@ __SPACE__
|
||||
|
||||
[#reference_optional_flat_map]
|
||||
|
||||
[: `template<class F> auto optional<T>::flat_map(F f) const& -> `['see below]` ;`]
|
||||
[: `template<class F> auto optional<T>::flat_map(F f) & -> `['see below]` ;`]
|
||||
[: `template<class F> constexpr auto optional<T>::flat_map(F f) const& -> `['see below]` ;`]
|
||||
[: `template<class F> constexpr auto optional<T>::flat_map(F f) & -> `['see below]` ;`]
|
||||
|
||||
* [*Requires:] The return type of expression `f(**this)` is `optional<U>` for some object or reference type `U`.
|
||||
* [*Effects:] `if (*this) return f(**this); else return none;`
|
||||
@@ -736,7 +745,7 @@ __SPACE__
|
||||
|
||||
[#reference_optional_flat_map_move]
|
||||
|
||||
[: `template<class F> auto optional<T>::flat_map(F f) && -> `['see below]` ;`]
|
||||
[: `template<class F> constexpr auto optional<T>::flat_map(F f) && -> `['see below]` ;`]
|
||||
|
||||
* [*Requires:] The return type of expression `f(std::move(**this))` is `optional<U>` for some object or reference type `U`.
|
||||
* [*Effects:] `if (*this) return f(std::move(**this)); else return none;`
|
||||
@@ -744,6 +753,26 @@ __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 ;`]
|
||||
@@ -793,8 +822,8 @@ __SPACE__
|
||||
|
||||
[#reference_optional_operator_arrow]
|
||||
|
||||
[: `T const* optional<T>::operator ->() const ;`]
|
||||
[: `T* optional<T>::operator ->() ;`]
|
||||
[: `constexpr T const* optional<T>::operator ->() const ;`]
|
||||
[: `constexpr T* optional<T>::operator ->() ;`]
|
||||
|
||||
* [*Requires: ] `*this` is initialized.
|
||||
* [*Returns:] A pointer to the contained value.
|
||||
@@ -812,44 +841,29 @@ __SPACE__
|
||||
|
||||
[#reference_optional_operator_bool]
|
||||
|
||||
[: `explicit optional<T>::operator bool() const noexcept ;`]
|
||||
[: `bool optional<T>::has_value() const noexcept ;`]
|
||||
[: `constexpr explicit optional<T>::operator bool() const noexcept ;`]
|
||||
[: `constexpr bool optional<T>::has_value() const noexcept ;`]
|
||||
|
||||
* [*Returns:] `get_ptr() != 0`.
|
||||
* [*Notes:] On compilers that do not support explicit conversion operators this falls back to safe-bool idiom.
|
||||
* [*Example:]
|
||||
``
|
||||
optional<T> def ;
|
||||
assert ( def == 0 );
|
||||
optional<T> opt ( v ) ;
|
||||
assert ( opt );
|
||||
assert ( opt != 0 );
|
||||
optional<int> oN;
|
||||
assert (!oN);
|
||||
assert (!oN.has_value());
|
||||
|
||||
optional<int> o1(1);
|
||||
assert (o1);
|
||||
assert (o1.has_value());
|
||||
assert (!!o1); // the "double-bang" idiom
|
||||
``
|
||||
|
||||
__SPACE__
|
||||
|
||||
[#reference_optional_operator_not]
|
||||
|
||||
[: `bool optional<T>::operator!() noexcept ;`]
|
||||
|
||||
* [*Returns:] If `*this` is uninitialized, `true`; else `false`.
|
||||
* [*Notes:] This operator is provided for those compilers which can't
|
||||
use the ['unspecified-bool-type operator] in certain boolean contexts.
|
||||
* [*Example:]
|
||||
``
|
||||
optional<T> opt ;
|
||||
assert ( !opt );
|
||||
*opt = some_T ;
|
||||
|
||||
// Notice the "double-bang" idiom here.
|
||||
assert ( !!opt ) ;
|
||||
``
|
||||
|
||||
__SPACE__
|
||||
|
||||
[#reference_optional_is_initialized]
|
||||
|
||||
[: `bool optional<T>::is_initialized() const ;`]
|
||||
[: `constexpr bool optional<T>::is_initialized() const ;`]
|
||||
|
||||
* [*Deprecated:] Same as `explicit operator bool () ;`
|
||||
|
||||
@@ -862,8 +876,8 @@ __SPACE__
|
||||
|
||||
[#reference_optional_ref_default_ctor]
|
||||
|
||||
[: `optional<T&>::optional() noexcept;`]
|
||||
[: `optional<T&>::optional(none_t) noexcept;`]
|
||||
[: `constexpr optional<T&>::optional() noexcept;`]
|
||||
[: `constexpr optional<T&>::optional(none_t) noexcept;`]
|
||||
|
||||
* [*Postconditions:] `bool(*this) == false`; `*this` refers to nothing.
|
||||
|
||||
@@ -963,7 +977,7 @@ __SPACE__
|
||||
|
||||
* [*Postconditions:] `bool(*this) == bool(rhs)`.
|
||||
|
||||
* [*Notes:] This behaviour is called ['rebinding semantics]. See [link boost_optional.tutorial.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:]
|
||||
``
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
[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]
|
||||
|
||||
+56
-40
@@ -9,7 +9,62 @@
|
||||
]
|
||||
|
||||
|
||||
[section Dependencies and Portability]
|
||||
[section Dependencies and Portability][#minimum_system_requirements]
|
||||
|
||||
|
||||
[section Minimum System Requirements]
|
||||
This library requires C++11 as minimum. However, in C++11 some features are disabled.
|
||||
|
||||
[section:constexpr Support for `constexpr`]
|
||||
|
||||
[section C++11]
|
||||
For compilers fully supporting C++11 (including unconstrained unions and ref-qualifiers),
|
||||
for trivially-destructible `T`s, `optional<T>` is a ['literal type] and its constructors
|
||||
with `this->has_value() == false` as postcondition:
|
||||
|
||||
* `optional()`,
|
||||
* `optional(none_t)`,
|
||||
|
||||
are ['core constant expressions]. Even for other `T`s, these constructors are guaranteed to
|
||||
perform ['constant initialization]: they are never subject to "initialization order fiasco".
|
||||
|
||||
Other constructors with `this->has_value() == true`
|
||||
as postcondition are core constant expressions if the expression required to initialize
|
||||
the contained value is a core constant expression. This includes constructors:
|
||||
|
||||
* `template <typename... Args> optional(in_place_init, Args&&...)`,
|
||||
* `template <typename U> optional(U&&)`,
|
||||
* `optional(const T&)`,
|
||||
* `optional(T&&)`.
|
||||
|
||||
Other constructors, including the copy and move constructos, are ['not] core constant expressions.
|
||||
|
||||
Member functions `.has_value`, `operator bool` and (non)equality comparisons with `none` are core-constant expressions for trivially-destructible `T`s.
|
||||
|
||||
Also all `const`-qualified non-static member functions and comparison operators are core constant expressions, if the corresponding operations on `T`
|
||||
are core constant expressions.
|
||||
[endsect]
|
||||
|
||||
[section C++14]
|
||||
For C++14 and higher this library, for trivially-destructible `T`s provides the `constexpr` interface for all mutable and non-mutable
|
||||
member functions, as long as:
|
||||
|
||||
* the corresponding operations on `T` are core constant expressions and
|
||||
* the member never attempts to change the `optional`'s state from not containing a value to containing a value.
|
||||
|
||||
[note For types that overload unary `operator&` (address) some member functions in `optional`, like `operator->`,
|
||||
cannot be implemented as `constexpr` on some compilers.]
|
||||
[endsect]
|
||||
|
||||
[section C++17]
|
||||
In C++17 all non-deprecated constructors are core constant expressions as long as
|
||||
`T` is a literal type and its constructor used is a core constant expression.
|
||||
[endsect]
|
||||
|
||||
[endsect:constexpr]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Dependencies]
|
||||
The implementation uses the following other Boost modules:
|
||||
@@ -17,50 +72,11 @@ The implementation uses the following other Boost modules:
|
||||
# assert
|
||||
# config
|
||||
# core
|
||||
# move
|
||||
# mpl
|
||||
# static_assert
|
||||
# throw_exception
|
||||
# type_traits
|
||||
# utility
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Emplace operations in older compilers][#optional_emplace_workaround]
|
||||
|
||||
Certain constructors and functions in the interface of `optional` perform a 'perfect forwarding' of arguments:
|
||||
|
||||
template<class... Args> optional(in_place_init_t, Args&&... args);
|
||||
template<class... Args> optional(in_place_init_if_t, bool condition, Args&&... args);
|
||||
template<class... Args> void emplace(Args&&... args);
|
||||
|
||||
On compilers that do not support variadic templates, each of these functions is substituted with two overloads, one forwarding a single argument, the other forwarding zero arguments. This forms the following set:
|
||||
|
||||
template<class Arg> optional(in_place_init_t, Arg&& arg);
|
||||
optional(in_place_init_t);
|
||||
|
||||
template<class Arg> optional(in_place_init_if_t, bool condition, Arg&& arg);
|
||||
optional(in_place_init_if_t, bool condition);
|
||||
|
||||
template<class Arg> void emplace(Arg&& arg);
|
||||
void emplace();
|
||||
|
||||
On compilers that do not support rvalue references, each of these functions is substituted with three overloads: taking `const` and non-`const` lvalue reference, and third forwarding zero arguments. This forms the following set:
|
||||
|
||||
template<class Arg> optional(in_place_init_t, const Arg& arg);
|
||||
template<class Arg> optional(in_place_init_t, Arg& arg);
|
||||
optional(in_place_init_t);
|
||||
|
||||
template<class Arg> optional(in_place_init_if_t, bool condition, const Arg& arg);
|
||||
template<class Arg> optional(in_place_init_if_t, bool condition, Arg& arg);
|
||||
optional(in_place_init_if_t, bool condition);
|
||||
|
||||
template<class Arg> void emplace(const Arg& arg);
|
||||
template<class Arg> void emplace(Arg& arg);
|
||||
void emplace();
|
||||
|
||||
This workaround addresses about 40% of all use cases. If this is insufficient, you need to resort to using [link boost_optional.tutorial.in_place_factories In-Place Factories].
|
||||
[endsect]
|
||||
|
||||
[section Optional Reference Binding][#optional_reference_binding]
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
[/
|
||||
Boost.Optional
|
||||
|
||||
Copyright (c) 2015 - 2024 Andrzej Krzemieński
|
||||
|
||||
Distributed under 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)
|
||||
]
|
||||
|
||||
|
||||
[section:std_comp Comparison with `std::optional`]
|
||||
|
||||
[table Comparison with `std::optional`
|
||||
[ [[*`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.] ]
|
||||
[ [] [`optional<vector<int>> o {in_place, {1, 2, 3}};`
|
||||
|
||||
`o.emplace({4, 5, 6});`] [No in-place initialization with initializer-list in `boost`.] ]
|
||||
[ [`optional<X> o {in_place_init_if, cond, a, b};`] [] [No syntax for conditional in-place initialization in `std`.] ]
|
||||
[ [`optional<X> o {cond, x};`] [] [No syntax for conditional initialization from `T` in `std`.] ]
|
||||
[ [`optional<T> o {U{}};`
|
||||
|
||||
`optional<T> o {optional<U>{}};`] [`optional<T> o = U{};`
|
||||
|
||||
`optional<T> o = optional<U>{}`] [Constructors form `U` and `optional<U>` are explicit in `boost` and implicit in `std`.] ]
|
||||
[ [] [`optional o = 1;`] [No clever deduction of of `optional`'s template parameters in initialization in `boost`. ]]
|
||||
[ [`optional<X const&> o;`] [] [No optional references in `std`.] ]
|
||||
[ [] [`constexpr optional<int> o;`] [No `constexpr` interface in `boost`.] ]
|
||||
[ [`o.map(&f);`
|
||||
|
||||
`o.flat_map(&of);` ] [`o.transform(&f);`
|
||||
|
||||
`o.and_then(&of);`] [Different names and signatures for monadic interface functions. `boost` takes callbacks by value, `std` by universal reference.] ]
|
||||
[ [] [`o.or_else(&of);`] [No `or_else` function in `boost`.] ]
|
||||
[ [`o.value_or_eval(&f);`] [] [No `value_or_eval` function in `std`.] ]
|
||||
[ [] [`optional<T>{} == U{}`;
|
||||
|
||||
`optional<T>{} == optional<U>{}`] [No comparisons with `U` or `optional<U>` in `boost`.] ]
|
||||
[ [`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]
|
||||
@@ -1,7 +1,7 @@
|
||||
[/
|
||||
Boost.Optional
|
||||
|
||||
Copyright (c) 2015 - 2023 Andrzej Krzemienski
|
||||
Copyright (c) 2015 - 2026 Andrzej Krzemienski
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -11,6 +11,72 @@
|
||||
|
||||
[section:relnotes Release Notes]
|
||||
|
||||
[heading Boost Release 1.91]
|
||||
|
||||
* For compilers with full C++11 support (including "unrestricted unions" and ref-qualifiers)
|
||||
changed the implementation from aligned storage to union storage. This enables the gradual
|
||||
`constexpr` support:
|
||||
|
||||
* In C++11, some constructors and `const`-qualified accessors become usable
|
||||
in compile-time contexts (are ['core constant expressions]) for types
|
||||
satisfying certain constraints.
|
||||
* In C++14 even some mutating operations become core constant expressions (those
|
||||
that do not require changing the state of `optional` from not having a value to
|
||||
having a value), for co-operating types.
|
||||
* In C++17 all constructors (including copy and move) become core constant expressions
|
||||
for co-operating types.
|
||||
|
||||
This addresses issues [@https://github.com/boostorg/optional/issues/132 #132] and [@https://github.com/boostorg/optional/issues/143 #143].
|
||||
|
||||
* *Breaking change.* In the said implementation, abandoned the mechanism for customizing
|
||||
`swap`. Hardly anyone knows about this mechanism and it was never documented.
|
||||
|
||||
* In the said implementation, applied a couple of small changes to get closer to the interface of `std::optional`:
|
||||
* Enabled syntax `o = {}` for putting optional objects to no-value state.
|
||||
* Enabled syntax `o.value_or({})`, which uses a default-constructed `T`.
|
||||
* Construct `o = u`, where `o` is of type `optional<T>` and `u` is of type `U` convertible to `T`,
|
||||
does not create a temporary `T`.
|
||||
|
||||
* In the said implementation, added a conversion from `optional<T>&` to `optional<T&>`. This addresses [@https://github.com/boostorg/optional/issues/142 issue #142].
|
||||
|
||||
* `none_t` is now `std::equality_comparable`, which means that `none_t` and `optional<T>`
|
||||
model concept `std::equality_comparable_with` (for `std::equality_comparable` `T`s),
|
||||
which means that you can `std::ranges::find(rng, boost::none)` for a range of optional objects.
|
||||
|
||||
* *Warning.* In the future releases we intend to introduce the range interface
|
||||
in `optional`, so that `std::ranges::range<optional<T>>` will be `true`.
|
||||
This may affect the overload resolution in programs that make decisions based
|
||||
on predicates such as `std::ranges::range`. For instance, the following code
|
||||
will start behaving differently:
|
||||
|
||||
```
|
||||
template <typename T>
|
||||
void serialize(T const& v)
|
||||
{
|
||||
if constexpr (std::ranges::range<T>)
|
||||
serialize_as_range(v);
|
||||
else if constexpr (custom::is_optional_like<T>)
|
||||
serialize_as_optional(v);
|
||||
else
|
||||
serialize_as_value(v);
|
||||
}
|
||||
```
|
||||
|
||||
[heading Boost Release 1.87]
|
||||
|
||||
* *Breaking change.* Dropped support for C++03. C++11 is now the required minimum; at least some C++11 features.
|
||||
* Dropped dependency on Boost.Utility.
|
||||
* Dropped dependency on Boost.Predef.
|
||||
* Dropped dependency on Boost.StaticAssert.
|
||||
* Dropped dependency on Boost.Move.
|
||||
* A bit faster implementation of some relational operations.
|
||||
* *Warning.* In the future releases we intend to introduce the range interface
|
||||
into `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`.
|
||||
* Tags `in_place_init` and `in_place_init_if` become `inline constexpr` and therewith leave smaller footprint in the executable. This addresses [@https://github.com/boostorg/optional/issues/103 issue #103].
|
||||
|
||||
|
||||
[heading Boost Release 1.85]
|
||||
|
||||
* Fixed the implementation for trivial types. Now it is slower, because it always initializes the `T`, but it avoids undefined behavior when `optional<T>` is copied. This fixes [@https://github.com/boostorg/optional/issues/108 issue #108].
|
||||
@@ -50,7 +50,7 @@ namespace {
|
||||
|
||||
#else
|
||||
|
||||
BOOST_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST none_t none ((none_t::init_tag()));
|
||||
BOOST_INLINE_CONSTEXPR none_t none ((none_t::init_tag()));
|
||||
|
||||
#endif // older definitions
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
// Copyright (C) 2014, 2015 Andrzej Krzemienski.
|
||||
// Copyright (C) 2014, 2024 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
|
||||
@@ -16,10 +16,16 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined (BOOST_NO_CXX11_RVALUE_REFERENCES) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_REF_QUALIFIERS) \
|
||||
|| defined(BOOST_NO_CXX11_LAMBDAS) || defined(BOOST_NO_CXX11_DECLTYPE_N3276) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || defined(BOOST_NO_CXX11_DEFAULTED_MOVES) || defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
|
||||
#if defined (BOOST_NO_CXX11_RVALUE_REFERENCES) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) \
|
||||
|| defined(BOOST_NO_CXX11_LAMBDAS) || defined(BOOST_NO_CXX11_DECLTYPE_N3276) \
|
||||
|| defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) \
|
||||
|| defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) || defined(BOOST_NO_CXX11_STATIC_ASSERT)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Optional 1.83 and will be removed in Boost.Optional 1.86.")
|
||||
#error "Boost.Optional requires some C++11 features since version 1.87. If you have an older C++ version use Boost.Optional version 1.86 or earlier."
|
||||
|
||||
#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.")
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,6 +46,11 @@ 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
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_EXPERIMENTAL_TRAITS_04NOV2017_HPP
|
||||
#define BOOST_OPTIONAL_DETAIL_EXPERIMENTAL_TRAITS_04NOV2017_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/predef.h>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
// The condition to use POD implementation
|
||||
@@ -23,8 +20,6 @@
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
#elif defined BOOST_OPTIONAL_CONFIG_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
#elif !defined BOOST_HAS_TRIVIAL_CONSTRUCTOR
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
#elif !defined BOOST_HAS_TRIVIAL_MOVE_ASSIGN
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
#elif !defined BOOST_HAS_TRIVIAL_MOVE_CONSTRUCTOR
|
||||
@@ -35,29 +30,6 @@
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
#elif !defined BOOST_HAS_TRIVIAL_DESTRUCTOR
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
#elif BOOST_WORKAROUND(BOOST_GCC, < 50000)
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
#endif
|
||||
|
||||
// GCC 5 or higher, or clang with libc++ or clang with libstdc++ 5 or higher
|
||||
#if __cplusplus >= 201103L
|
||||
# if BOOST_WORKAROUND(BOOST_GCC, >= 50000)
|
||||
# define BOOST_OPTIONAL_DETAIL_USE_STD_TYPE_TRAITS
|
||||
# elif (defined BOOST_CLANG)
|
||||
# if BOOST_LIB_STD_CXX > 0
|
||||
# define BOOST_OPTIONAL_DETAIL_USE_STD_TYPE_TRAITS
|
||||
# elif BOOST_LIB_STD_GNU >= 441200023 && BOOST_LIB_STD_GNU != 450600023 && BOOST_LIB_STD_GNU != 450600026 && BOOST_LIB_STD_GNU != 460800003 && BOOST_LIB_STD_GNU != 450400026 && BOOST_LIB_STD_GNU != 460700026
|
||||
# define BOOST_OPTIONAL_DETAIL_USE_STD_TYPE_TRAITS
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_USE_STD_TYPE_TRAITS
|
||||
# define BOOST_OPTIONAL_DETAIL_HAS_TRIVIAL_CTOR(T) BOOST_HAS_TRIVIAL_CONSTRUCTOR(T)
|
||||
#else
|
||||
# include <type_traits>
|
||||
# define BOOST_OPTIONAL_DETAIL_HAS_TRIVIAL_CTOR(T) std::is_trivially_default_constructible<T>::value
|
||||
#endif
|
||||
|
||||
|
||||
@@ -65,7 +37,7 @@ namespace boost { namespace optional_detail {
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
template <typename T>
|
||||
struct is_type_trivially_copyable
|
||||
struct is_trivially_semiregular
|
||||
: boost::conditional<(boost::has_trivial_copy_constructor<T>::value &&
|
||||
boost::has_trivial_move_constructor<T>::value &&
|
||||
boost::has_trivial_destructor<T>::value &&
|
||||
@@ -75,30 +47,13 @@ struct is_type_trivially_copyable
|
||||
{};
|
||||
#else
|
||||
template <typename T>
|
||||
struct is_type_trivially_copyable
|
||||
struct is_trivially_semiregular
|
||||
: boost::conditional<(boost::is_scalar<T>::value && !boost::is_const<T>::value && !boost::is_volatile<T>::value),
|
||||
boost::true_type, boost::false_type>::type
|
||||
{};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
template <typename T>
|
||||
struct optional_uses_direct_storage_for_
|
||||
: boost::conditional< (is_type_trivially_copyable<T>::value && BOOST_OPTIONAL_DETAIL_HAS_TRIVIAL_CTOR(T)) ||
|
||||
(boost::is_scalar<T>::value && !boost::is_const<T>::value && !boost::is_volatile<T>::value)
|
||||
, boost::true_type, boost::false_type>::type
|
||||
{};
|
||||
#else
|
||||
template <typename T>
|
||||
struct optional_uses_direct_storage_for_
|
||||
: boost::conditional<(boost::is_scalar<T>::value && !boost::is_const<T>::value && !boost::is_volatile<T>::value)
|
||||
, boost::true_type, boost::false_type>::type
|
||||
{};
|
||||
#endif
|
||||
|
||||
|
||||
}} // boost::optional_detail
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
// Copyright (C) 2024 Ryan Malcolm Underwood.
|
||||
// Copyright (C) 2026 Andrzej Krzemieński.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the authors at:
|
||||
// akrzemi1@gmail.com
|
||||
// typenametea@gmail.com
|
||||
//
|
||||
//
|
||||
// This header provides definitions required by any specialization of
|
||||
// optional<>.
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_COMMON_DEFS_01FEB2026_HPP
|
||||
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_COMMON_DEFS_01FEB2026_HPP
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <type_traits>
|
||||
#include <boost/optional/detail/optional_factory_support.hpp>
|
||||
|
||||
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#endif
|
||||
|
||||
// This is needed for C++11, where constexpr functions must contain a single expression.
|
||||
// We want to assert and then return.
|
||||
#if defined NDEBUG
|
||||
# define BOOST_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
|
||||
#else
|
||||
# define BOOST_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{BOOST_ASSERT(!(#CHECK));}(), (EXPR)))
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
# define BOOST_OPTIONAL_DECAY(T) typename ::std::decay<T>::type
|
||||
# define BOOST_OPTIONAL_IS_TAGGED(TAG, U) ::std::is_base_of<TAG, BOOST_OPTIONAL_DECAY(U)>
|
||||
#else
|
||||
# define BOOST_OPTIONAL_DECAY(T) BOOST_DEDUCED_TYPENAME boost::decay<T>::type
|
||||
# define BOOST_OPTIONAL_IS_TAGGED(TAG, U) boost::is_base_of<TAG, BOOST_OPTIONAL_DECAY(U)>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <typename T> class optional;
|
||||
|
||||
|
||||
// Boost-wide tags for recognizing "factories": a C++03 workaround
|
||||
// for perfect forwarding.
|
||||
class in_place_factory_base;
|
||||
class typed_in_place_factory_base;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
// Traits for recognizing in-place factories
|
||||
namespace boost { namespace optional_detail {
|
||||
|
||||
template <typename U>
|
||||
struct is_in_place_factory : BOOST_OPTIONAL_IS_TAGGED(boost::in_place_factory_base, U) {};
|
||||
|
||||
template <typename U>
|
||||
struct is_typed_in_place_factory : BOOST_OPTIONAL_IS_TAGGED(boost::typed_in_place_factory_base, U) {};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
/** This is a set of declarations that repeat those from the Standard Library
|
||||
header <utility> but without having to drag its entire content. They also
|
||||
add missing capabilities, like constexpr, in older compiler versions.
|
||||
*/
|
||||
namespace boost { namespace optional_detail {
|
||||
|
||||
template <typename T>
|
||||
T declval_();
|
||||
|
||||
template <class T>
|
||||
inline constexpr T&& forward_(typename ::std::remove_reference<T>::type& t) noexcept
|
||||
{
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline constexpr T&& forward_(typename ::std::remove_reference<T>::type&& t) noexcept
|
||||
{
|
||||
static_assert(!::std::is_lvalue_reference<T>::value, "Can not forward an rvalue as an lvalue.");
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline constexpr typename ::std::remove_reference<T>::type&& move_(T&& t) noexcept
|
||||
{
|
||||
return static_cast<typename ::std::remove_reference<T>::type&&>(t);
|
||||
}
|
||||
|
||||
}} // namespace boost::optional_detail
|
||||
|
||||
|
||||
/** This is a set of declarations that are not part of this library's interface.
|
||||
They are implementation details.
|
||||
*/
|
||||
namespace boost { namespace optional_detail {
|
||||
|
||||
/** This struct is used for tagging types that want to be recognized as
|
||||
`optional`. If your class inherits directly or indirectly from `optional_tag`
|
||||
the type traits and overloads will treat it as `optional<>`.
|
||||
*/
|
||||
struct optional_tag {};
|
||||
|
||||
/** `optional_value_type`: given type `X`:
|
||||
* if `X` is an instance of `boost::optional`, returns its value_type,
|
||||
* otherwise we get a SFINAE-able error.
|
||||
*/
|
||||
template <typename X>
|
||||
struct optional_value_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
struct optional_value_type< ::boost::optional<U> >
|
||||
{
|
||||
typedef U type;
|
||||
};
|
||||
|
||||
|
||||
/** This is an approximation of a 1-argument C++17 std::invoke_result.
|
||||
*/
|
||||
template <typename F, typename Ref, typename Rslt = decltype(declval_<F>()(declval_<Ref>()))>
|
||||
struct result_of
|
||||
{
|
||||
typedef Rslt type;
|
||||
};
|
||||
|
||||
/** This type trait returns the following given the expression `f(ref)`:
|
||||
* if the result is a specialization of `boost::optional`: its value_type,
|
||||
* otherwise a SFINAE-able error.
|
||||
*/
|
||||
template <typename F, typename Ref, typename Rslt = typename optional_value_type<typename result_of<F, Ref>::type>::type>
|
||||
struct result_value_type
|
||||
{
|
||||
typedef Rslt type;
|
||||
};
|
||||
|
||||
}} // namespace boost::optional_detail
|
||||
|
||||
|
||||
/** The following two tags are intended to be used by library users.
|
||||
The additional namespace is used in order to prevent the ADL from
|
||||
dragging all functions from namespace `boost` in any unqualified name lookup
|
||||
when these tags are involved.
|
||||
*/
|
||||
namespace boost {
|
||||
|
||||
namespace optional_ns {
|
||||
|
||||
/// a tag for in-place initialization of contained value
|
||||
struct in_place_init_t
|
||||
{
|
||||
struct init_tag{};
|
||||
BOOST_CONSTEXPR explicit in_place_init_t(init_tag){}
|
||||
};
|
||||
BOOST_INLINE_CONSTEXPR in_place_init_t in_place_init ((in_place_init_t::init_tag()));
|
||||
|
||||
/// a tag for conditional in-place initialization of contained value
|
||||
struct in_place_init_if_t
|
||||
{
|
||||
struct init_tag{};
|
||||
BOOST_CONSTEXPR explicit in_place_init_if_t(init_tag){}
|
||||
};
|
||||
BOOST_INLINE_CONSTEXPR in_place_init_if_t in_place_init_if ((in_place_init_if_t::init_tag()));
|
||||
|
||||
} // namespace optional_ns
|
||||
|
||||
using optional_ns::in_place_init_t;
|
||||
using optional_ns::in_place_init;
|
||||
using optional_ns::in_place_init_if_t;
|
||||
using optional_ns::in_place_init_if;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_OPTIONAL_DETAIL_OPTIONAL_COMMON_DEFS_01FEB2026_HPP
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#if (defined BOOST_NO_CXX11_RVALUE_REFERENCES) || (defined BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES)
|
||||
#if (defined BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES)
|
||||
# define BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
#endif
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
#endif // defined(__GNUC__)
|
||||
|
||||
#if (defined __GNUC__) && (!defined BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
#if (defined __GNUC__)
|
||||
// On some initial rvalue reference implementations GCC does it in a strange way,
|
||||
// preferring perfect-forwarding constructor to implicit copy constructor.
|
||||
|
||||
@@ -132,4 +132,13 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BOOST_NO_CXX11_REF_QUALIFIERS
|
||||
# define BOOST_OPTIONAL_CONST_REF_QUAL const
|
||||
# define BOOST_OPTIONAL_REF_QUAL
|
||||
#else
|
||||
# define BOOST_OPTIONAL_CONST_REF_QUAL const&
|
||||
# define BOOST_OPTIONAL_REF_QUAL &
|
||||
#endif
|
||||
|
||||
|
||||
#endif // header guard
|
||||
|
||||
@@ -27,10 +27,4 @@ namespace boost_optional_detail
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class in_place_factory_base ;
|
||||
class typed_in_place_factory_base ;
|
||||
}
|
||||
|
||||
#endif // header guard
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_HASH_AJK_20MAY2022_HPP
|
||||
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_HASH_AJK_20MAY2022_HPP
|
||||
|
||||
#include <boost/optional/optional_fwd.hpp>
|
||||
//#include <boost/optional/optional_fwd.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if !defined(BOOST_OPTIONAL_CONFIG_DO_NOT_SPECIALIZE_STD_HASH) && !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL)
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
|
||||
// Copyright (C) 2014 - 2026 Andrzej Krzemieński.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the authors at:
|
||||
// fernando_cacciola@hotmail.com
|
||||
// akrzemi1@gmail.com
|
||||
//
|
||||
// You can file a GitHub issue at:
|
||||
// https://github.com/boostorg/optional/issues
|
||||
|
||||
|
||||
// This header provides definitions rof nonmember functions that still constitute
|
||||
// the interface for class optional<>.
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_NONMEMBER_INTERFACE_01FEB2026_HPP
|
||||
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_NONMEMBER_INTERFACE_01FEB2026_HPP
|
||||
|
||||
namespace boost {
|
||||
|
||||
|
||||
template <class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
optional<BOOST_OPTIONAL_DECAY(T)> make_optional ( T && v )
|
||||
{
|
||||
return optional<BOOST_OPTIONAL_DECAY(T)>(optional_detail::forward_<T>(v));
|
||||
}
|
||||
|
||||
// Returns optional<T>(cond,v)
|
||||
template <class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
optional<BOOST_OPTIONAL_DECAY(T)> make_optional ( bool cond, T && v )
|
||||
{
|
||||
return optional<BOOST_OPTIONAL_DECAY(T)>(cond,optional_detail::forward_<T>(v));
|
||||
}
|
||||
|
||||
|
||||
// Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
|
||||
// No-throw
|
||||
template <class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
|
||||
get ( optional<T> const& opt )
|
||||
{
|
||||
return opt.get() ;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::reference_type
|
||||
get ( optional<T>& opt )
|
||||
{
|
||||
return opt.get() ;
|
||||
}
|
||||
|
||||
// Returns a pointer to the value if this is initialized, otherwise, returns NULL.
|
||||
// No-throw
|
||||
template<class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
|
||||
get ( optional<T> const* opt )
|
||||
{
|
||||
return opt->get_ptr() ;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
|
||||
get ( optional<T>* opt )
|
||||
{
|
||||
return opt->get_ptr() ;
|
||||
}
|
||||
|
||||
// Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
|
||||
// No-throw
|
||||
template<class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
|
||||
get_optional_value_or ( optional<T> const& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type v )
|
||||
{
|
||||
return opt.get_value_or(v) ;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::reference_type
|
||||
get_optional_value_or ( optional<T>& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_type v )
|
||||
{
|
||||
return opt.get_value_or(v) ;
|
||||
}
|
||||
|
||||
// Returns a pointer to the value if this is initialized, otherwise, returns NULL.
|
||||
// No-throw
|
||||
template<class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
|
||||
get_pointer ( optional<T> const& opt )
|
||||
{
|
||||
return opt.get_ptr() ;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
|
||||
get_pointer ( optional<T>& opt )
|
||||
{
|
||||
return opt.get_ptr() ;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_OPTIONAL_DETAIL_OPTIONAL_NONMEMBER_INTERFACE_01FEB2026_HPP
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2015-2018 Andrzej Krzemienski.
|
||||
// Copyright (C) 2015-2024 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
|
||||
@@ -13,9 +13,21 @@
|
||||
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_REFERENCE_SPEC_AJK_03OCT2015_HPP
|
||||
|
||||
#ifdef BOOST_OPTIONAL_CONFIG_NO_PROPER_ASSIGN_FROM_CONST_INT
|
||||
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
# define BOOST_OPTIONAL_TT_PREFIX ::std
|
||||
#else
|
||||
# define BOOST_OPTIONAL_TT_PREFIX boost
|
||||
# define BOOST_OPTIONAL_REQUIRES(...) BOOST_DEDUCED_TYPENAME boost::enable_if_c<__VA_ARGS__::value, bool>::type = false
|
||||
#endif
|
||||
|
||||
# define BOOST_OPTIONAL_TT_TYPE(...) BOOST_DEDUCED_TYPENAME BOOST_OPTIONAL_TT_PREFIX::__VA_ARGS__::type
|
||||
# define BOOST_OPTIONAL_TT_PRED(...) BOOST_OPTIONAL_TT_PREFIX::__VA_ARGS__::value
|
||||
|
||||
# if 1
|
||||
|
||||
@@ -29,17 +41,17 @@ template <class From>
|
||||
void prevent_binding_rvalue()
|
||||
{
|
||||
#ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES
|
||||
BOOST_STATIC_ASSERT_MSG(boost::is_lvalue_reference<From>::value,
|
||||
"binding rvalue references to optional lvalue references is disallowed");
|
||||
#endif
|
||||
static_assert(BOOST_OPTIONAL_TT_PRED(is_lvalue_reference<From>),
|
||||
"binding rvalue references to optional lvalue references is disallowed");
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type& forward_reference(T&& r)
|
||||
BOOST_OPTIONAL_TT_TYPE(remove_reference<T>)& forward_reference(T&& r)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(boost::is_lvalue_reference<T>::value,
|
||||
"binding rvalue references to optional lvalue references is disallowed");
|
||||
return boost::forward<T>(r);
|
||||
static_assert(BOOST_OPTIONAL_TT_PRED(is_lvalue_reference<T>),
|
||||
"binding rvalue references to optional lvalue references is disallowed");
|
||||
return optional_detail::forward_<T>(r);
|
||||
}
|
||||
|
||||
#endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
@@ -48,14 +60,14 @@ BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type& forward_reference(T&& r
|
||||
template <class T>
|
||||
struct is_const_integral
|
||||
{
|
||||
static const bool value = boost::is_const<T>::value && boost::is_integral<T>::value;
|
||||
static const bool value = BOOST_OPTIONAL_TT_PRED(is_const<T>) && BOOST_OPTIONAL_TT_PRED(is_integral<T>);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_const_integral_bad_for_conversion
|
||||
{
|
||||
#if (!defined BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES) && (defined BOOST_OPTIONAL_CONFIG_NO_PROPER_CONVERT_FROM_CONST_INT)
|
||||
static const bool value = boost::is_const<T>::value && boost::is_integral<T>::value;
|
||||
static const bool value = is_const_integral<T>::value;
|
||||
#else
|
||||
static const bool value = false;
|
||||
#endif
|
||||
@@ -68,10 +80,10 @@ void prevent_assignment_from_false_const_integral()
|
||||
#ifdef BOOST_OPTIONAL_CONFIG_NO_PROPER_ASSIGN_FROM_CONST_INT
|
||||
// MSVC compiler without rvalue references: we need to disable the assignment from
|
||||
// const integral lvalue reference, as it may be an invalid temporary
|
||||
BOOST_STATIC_ASSERT_MSG(!is_const_integral<From>::value,
|
||||
"binding const lvalue references to integral types is disabled in this compiler");
|
||||
static_assert(!is_const_integral<From>::value,
|
||||
"binding const lvalue references to integral types is disabled in this compiler");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -90,15 +102,15 @@ struct is_optional_< ::boost::optional<U> >
|
||||
template <class T>
|
||||
struct is_no_optional
|
||||
{
|
||||
static const bool value = !is_optional_<BOOST_DEDUCED_TYPENAME boost::decay<T>::type>::value;
|
||||
static const bool value = !is_optional_<BOOST_OPTIONAL_DECAY(T)>::value;
|
||||
};
|
||||
|
||||
|
||||
template <class T, class U>
|
||||
struct is_same_decayed
|
||||
{
|
||||
static const bool value = ::boost::is_same<T, BOOST_DEDUCED_TYPENAME ::boost::remove_reference<U>::type>::value
|
||||
|| ::boost::is_same<T, const BOOST_DEDUCED_TYPENAME ::boost::remove_reference<U>::type>::value;
|
||||
static const bool value = BOOST_OPTIONAL_TT_PRED(is_same<T, BOOST_OPTIONAL_TT_TYPE(remove_reference<U>)>)
|
||||
|| BOOST_OPTIONAL_TT_PRED(is_same<T, const BOOST_OPTIONAL_TT_TYPE(remove_reference<U>)>);
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
@@ -114,7 +126,7 @@ template <class T>
|
||||
class optional<T&> : public optional_detail::optional_tag
|
||||
{
|
||||
T* ptr_;
|
||||
|
||||
|
||||
public:
|
||||
typedef T& value_type;
|
||||
typedef T& reference_type;
|
||||
@@ -122,152 +134,166 @@ public:
|
||||
typedef T& rval_reference_type;
|
||||
typedef T* pointer_type;
|
||||
typedef T* pointer_const_type;
|
||||
|
||||
optional() BOOST_NOEXCEPT : ptr_() {}
|
||||
optional(none_t) BOOST_NOEXCEPT : ptr_() {}
|
||||
|
||||
BOOST_CONSTEXPR optional() BOOST_NOEXCEPT : ptr_() {}
|
||||
BOOST_CONSTEXPR optional(none_t) BOOST_NOEXCEPT : ptr_() {}
|
||||
|
||||
template <class U>
|
||||
explicit optional(const optional<U&>& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {}
|
||||
optional(const optional& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {}
|
||||
|
||||
BOOST_CONSTEXPR explicit optional(const optional<U&>& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {}
|
||||
BOOST_CONSTEXPR optional(const optional& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {}
|
||||
|
||||
// the following two implement a 'conditionally explicit' constructor: condition is a hack for buggy compilers with screwed conversion construction from const int
|
||||
template <class U>
|
||||
explicit optional(U& rhs, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::is_same_decayed<T, U>::value && detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(rhs)) {}
|
||||
|
||||
template <class U>
|
||||
optional(U& rhs, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::is_same_decayed<T, U>::value && !detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(rhs)) {}
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>),
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_const_integral_bad_for_conversion<U>)>
|
||||
BOOST_CONSTEXPR explicit
|
||||
optional(U& rhs) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(rhs)) {}
|
||||
|
||||
optional& operator=(const optional& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
|
||||
template <class U>
|
||||
optional& operator=(const optional<U&>& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
|
||||
optional& operator=(none_t) BOOST_NOEXCEPT { ptr_ = 0; return *this; }
|
||||
|
||||
|
||||
void swap(optional& rhs) BOOST_NOEXCEPT { std::swap(ptr_, rhs.ptr_); }
|
||||
T& get() const { BOOST_ASSERT(ptr_); return *ptr_; }
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_same_decayed<T, U>),
|
||||
BOOST_OPTIONAL_REQUIRES(!detail::is_const_integral_bad_for_conversion<U>)>
|
||||
BOOST_CONSTEXPR
|
||||
optional(U& rhs) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(rhs)) {}
|
||||
|
||||
T* get_ptr() const BOOST_NOEXCEPT { return ptr_; }
|
||||
T* operator->() const { BOOST_ASSERT(ptr_); return ptr_; }
|
||||
T& operator*() const { BOOST_ASSERT(ptr_); return *ptr_; }
|
||||
|
||||
T& value() const
|
||||
BOOST_CXX14_CONSTEXPR optional& operator=(const optional& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
|
||||
template <class U>
|
||||
BOOST_CXX14_CONSTEXPR optional& operator=(const optional<U&>& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; }
|
||||
BOOST_CXX14_CONSTEXPR optional& operator=(none_t) BOOST_NOEXCEPT { ptr_ = 0; return *this; }
|
||||
|
||||
|
||||
BOOST_CXX14_CONSTEXPR void swap(optional& rhs) BOOST_NOEXCEPT { ::std::swap(ptr_, rhs.ptr_); }
|
||||
constexpr T& get() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, *ptr_); }
|
||||
|
||||
constexpr T* get_ptr() const BOOST_NOEXCEPT { return ptr_; }
|
||||
constexpr T* operator->() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, ptr_); }
|
||||
constexpr T& operator*() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(ptr_, *ptr_); }
|
||||
|
||||
constexpr T& value() const
|
||||
{
|
||||
if (this->is_initialized())
|
||||
return this->get();
|
||||
else
|
||||
throw_exception(bad_optional_access());
|
||||
return this->is_initialized() ?
|
||||
this->get() :
|
||||
(boost::throw_exception(boost::bad_optional_access()), this->get());
|
||||
}
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT { return ptr_ == 0; }
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
void reset() BOOST_NOEXCEPT { ptr_ = 0; }
|
||||
|
||||
bool is_initialized() const BOOST_NOEXCEPT { return ptr_ != 0; }
|
||||
bool has_value() const BOOST_NOEXCEPT { return ptr_ != 0; }
|
||||
|
||||
constexpr explicit operator bool() const BOOST_NOEXCEPT { return ptr_ != 0; }
|
||||
|
||||
BOOST_CXX14_CONSTEXPR void reset() BOOST_NOEXCEPT { ptr_ = 0; }
|
||||
|
||||
constexpr bool is_initialized() const BOOST_NOEXCEPT { return ptr_ != 0; }
|
||||
constexpr bool has_value() const BOOST_NOEXCEPT { return ptr_ != 0; }
|
||||
|
||||
template <typename F>
|
||||
optional<typename boost::result_of<F(T&)>::type> map(F f) const
|
||||
constexpr optional<typename optional_detail::result_of<F, reference_const_type>::type>
|
||||
map(F f) const
|
||||
{
|
||||
if (this->has_value())
|
||||
return f(this->get());
|
||||
else
|
||||
return none;
|
||||
return this->has_value() ?
|
||||
f(get()) :
|
||||
optional<typename optional_detail::result_of<F, reference_const_type>::type>();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
optional<typename optional_detail::optional_value_type<typename boost::result_of<F(T&)>::type>::type> flat_map(F f) const
|
||||
constexpr optional<typename optional_detail::result_value_type<F, reference_const_type>::type>
|
||||
flat_map(F f) const
|
||||
{
|
||||
if (this->has_value())
|
||||
return f(get());
|
||||
else
|
||||
return none;
|
||||
return this->has_value() ?
|
||||
f(get()) :
|
||||
optional<typename optional_detail::result_value_type<F, reference_const_type>::type>();
|
||||
}
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
|
||||
optional(T&& /* rhs */) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<T&&>(); }
|
||||
|
||||
template <class R>
|
||||
optional(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::no_unboxing_cond<T, R>, bool>::type = true) BOOST_NOEXCEPT
|
||||
|
||||
template <class R, BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, R>)>
|
||||
BOOST_CXX14_CONSTEXPR optional(R&& r) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(r)) { detail::prevent_binding_rvalue<R>(); }
|
||||
|
||||
template <class R>
|
||||
optional(bool cond, R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT
|
||||
|
||||
template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
|
||||
BOOST_CXX14_CONSTEXPR optional(bool cond, R&& r) BOOST_NOEXCEPT
|
||||
: ptr_(cond ? boost::addressof(r) : 0) { detail::prevent_binding_rvalue<R>(); }
|
||||
|
||||
template <class R>
|
||||
BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, optional<T&>&>::type
|
||||
|
||||
template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
|
||||
BOOST_CXX14_CONSTEXPR optional<T&>&
|
||||
operator=(R&& r) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); return *this; }
|
||||
|
||||
template <class R>
|
||||
void emplace(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT
|
||||
|
||||
template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
|
||||
BOOST_CXX14_CONSTEXPR void emplace(R&& r) BOOST_NOEXCEPT
|
||||
{ detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); }
|
||||
|
||||
template <class R>
|
||||
T& get_value_or(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) const BOOST_NOEXCEPT
|
||||
|
||||
template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
|
||||
BOOST_CXX14_CONSTEXPR T& get_value_or(R&& r) const BOOST_NOEXCEPT
|
||||
{ detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; }
|
||||
|
||||
template <class R>
|
||||
T& value_or(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) const BOOST_NOEXCEPT
|
||||
|
||||
template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
|
||||
BOOST_CXX14_CONSTEXPR T& value_or(R&& r) const BOOST_NOEXCEPT
|
||||
{ detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; }
|
||||
|
||||
template <class R>
|
||||
void reset(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT
|
||||
|
||||
template <class R, BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<R>)>
|
||||
BOOST_CXX14_CONSTEXPR void reset(R&& r) BOOST_NOEXCEPT
|
||||
{ detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); }
|
||||
|
||||
|
||||
template <class F>
|
||||
T& value_or_eval(F f) const { return ptr_ ? *ptr_ : detail::forward_reference(f()); }
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T& value_or_eval(F f) const { return ptr_ ? *ptr_ : detail::forward_reference(f()); }
|
||||
|
||||
#else // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
|
||||
|
||||
// the following two implement a 'conditionally explicit' constructor
|
||||
template <class U>
|
||||
explicit optional(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::no_unboxing_cond<T, U>::value && detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(v)) { }
|
||||
|
||||
template <class U>
|
||||
optional(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::no_unboxing_cond<T, U>::value && !detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(v)) { }
|
||||
|
||||
template <class U>
|
||||
optional(bool cond, U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT : ptr_(cond ? boost::addressof(v) : 0) {}
|
||||
|
||||
template <class U>
|
||||
BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, optional<T&>&>::type
|
||||
operator=(U& v) BOOST_NOEXCEPT
|
||||
// the following two implement a 'conditionally explicit' constructor
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, U>),
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_const_integral_bad_for_conversion<U>)>
|
||||
BOOST_CXX14_CONSTEXPR explicit optional(U& v) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(v)) { }
|
||||
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::no_unboxing_cond<T, U>),
|
||||
BOOST_OPTIONAL_REQUIRES(!detail::is_const_integral_bad_for_conversion<U>)>
|
||||
BOOST_CXX14_CONSTEXPR optional(U& v) BOOST_NOEXCEPT
|
||||
: ptr_(boost::addressof(v)) { }
|
||||
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
|
||||
BOOST_CXX14_CONSTEXPR optional(bool cond, U& v) BOOST_NOEXCEPT : ptr_(cond ? boost::addressof(v) : 0) {}
|
||||
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
|
||||
BOOST_CXX14_CONSTEXPR
|
||||
optional<T&>& operator=(U& v) BOOST_NOEXCEPT
|
||||
{
|
||||
detail::prevent_assignment_from_false_const_integral<U>();
|
||||
ptr_ = boost::addressof(v); return *this;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
void emplace(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
|
||||
BOOST_CXX14_CONSTEXPR void emplace(U& v) BOOST_NOEXCEPT
|
||||
{ ptr_ = boost::addressof(v); }
|
||||
|
||||
template <class U>
|
||||
T& get_value_or(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) const BOOST_NOEXCEPT
|
||||
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
|
||||
BOOST_CXX14_CONSTEXPR T& get_value_or(U& v) const BOOST_NOEXCEPT
|
||||
{ return ptr_ ? *ptr_ : v; }
|
||||
|
||||
template <class U>
|
||||
T& value_or(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) const BOOST_NOEXCEPT
|
||||
{ return ptr_ ? *ptr_ : v; }
|
||||
|
||||
template <class U>
|
||||
void reset(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT
|
||||
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
|
||||
BOOST_CXX14_CONSTEXPR T& value_or(U& v) const BOOST_NOEXCEPT
|
||||
{ return ptr_ ? *ptr_ : v; }
|
||||
|
||||
template <class U,
|
||||
BOOST_OPTIONAL_REQUIRES(detail::is_no_optional<U>)>
|
||||
BOOST_CXX14_CONSTEXPR void reset(U& v) BOOST_NOEXCEPT
|
||||
{ ptr_ = boost::addressof(v); }
|
||||
|
||||
|
||||
template <class F>
|
||||
T& value_or_eval(F f) const { return ptr_ ? *ptr_ : f(); }
|
||||
|
||||
BOOST_CXX14_CONSTEXPR T& value_or_eval(F f) const { return ptr_ ? *ptr_ : f(); }
|
||||
|
||||
#endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void swap ( optional<T&>& x, optional<T&>& y) BOOST_NOEXCEPT
|
||||
template <class T>
|
||||
BOOST_CXX14_CONSTEXPR void swap ( optional<T&>& x, optional<T&>& y) BOOST_NOEXCEPT
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
|
||||
// Copyright (C) 2015 Andrzej Krzemienski.
|
||||
// Copyright (C) 2015, 2024, 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
|
||||
@@ -16,7 +16,8 @@
|
||||
namespace boost {
|
||||
|
||||
// optional's relational operators ( ==, !=, <, >, <=, >= ) have deep-semantics (compare values).
|
||||
// WARNING: This is UNLIKE pointers. Use equal_pointees()/less_pointees() in generic code instead.
|
||||
// WARNING: This is UNLIKE pointers. Use equal_pointees()/less_pointees() in generic code instead,
|
||||
// to obtain the same semantic for pointers.
|
||||
|
||||
|
||||
//
|
||||
@@ -24,32 +25,32 @@ namespace boost {
|
||||
//
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator == ( optional<T> const& x, optional<T> const& y )
|
||||
{ return bool(x) && bool(y) ? *x == *y : bool(x) == bool(y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator < ( optional<T> const& x, optional<T> const& y )
|
||||
{ return less_pointees(x,y); }
|
||||
{ return !y ? false : (!x ? true : (*x) < (*y)); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator != ( optional<T> const& x, optional<T> const& y )
|
||||
{ return !( x == y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator > ( optional<T> const& x, optional<T> const& y )
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator <= ( optional<T> const& x, optional<T> const& y )
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator >= ( optional<T> const& x, optional<T> const& y )
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
@@ -58,32 +59,32 @@ bool operator >= ( optional<T> const& x, optional<T> const& y )
|
||||
// optional<T> vs T cases
|
||||
//
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator == ( optional<T> const& x, T const& y )
|
||||
{ return equal_pointees(x, optional<T>(y)); }
|
||||
{ return x && (*x == y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator < ( optional<T> const& x, T const& y )
|
||||
{ return less_pointees(x, optional<T>(y)); }
|
||||
{ return (!x) || (*x < y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator != ( optional<T> const& x, T const& y )
|
||||
{ return !( x == y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator > ( optional<T> const& x, T const& y )
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator <= ( optional<T> const& x, T const& y )
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator >= ( optional<T> const& x, T const& y )
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
@@ -92,32 +93,32 @@ bool operator >= ( optional<T> const& x, T const& y )
|
||||
//
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator == ( T const& x, optional<T> const& y )
|
||||
{ return equal_pointees( optional<T>(x), y ); }
|
||||
{ return y && (x == *y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator < ( T const& x, optional<T> const& y )
|
||||
{ return less_pointees( optional<T>(x), y ); }
|
||||
{ return y && (x < *y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator != ( T const& x, optional<T> const& y )
|
||||
{ return !( x == y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator > ( T const& x, optional<T> const& y )
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator <= ( T const& x, optional<T> const& y )
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator >= ( T const& x, optional<T> const& y )
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
@@ -127,33 +128,33 @@ bool operator >= ( T const& x, optional<T> const& y )
|
||||
//
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator == ( optional<T> const& x, none_t ) BOOST_NOEXCEPT
|
||||
{ return !x; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator < ( optional<T> const& x, none_t )
|
||||
{ return less_pointees(x,optional<T>() ); }
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator < ( optional<T> const&, none_t ) BOOST_NOEXCEPT
|
||||
{ return false; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator != ( optional<T> const& x, none_t ) BOOST_NOEXCEPT
|
||||
{ return bool(x); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator > ( optional<T> const& x, none_t y )
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator > ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator <= ( optional<T> const& x, none_t y )
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator <= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator >= ( optional<T> const& x, none_t y )
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator >= ( optional<T> const& x, none_t y ) BOOST_NOEXCEPT
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
//
|
||||
@@ -161,36 +162,35 @@ bool operator >= ( optional<T> const& x, none_t y )
|
||||
//
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator == ( none_t , optional<T> const& y ) BOOST_NOEXCEPT
|
||||
{ return !y; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator < ( none_t , optional<T> const& y )
|
||||
{ return less_pointees(optional<T>() ,y); }
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator < ( none_t , optional<T> const& y ) BOOST_NOEXCEPT
|
||||
{ return bool(y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator != ( none_t, optional<T> const& y ) BOOST_NOEXCEPT
|
||||
{ return bool(y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator > ( none_t x, optional<T> const& y )
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator > ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator <= ( none_t x, optional<T> const& y )
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator <= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator >= ( none_t x, optional<T> const& y )
|
||||
inline BOOST_CONSTEXPR
|
||||
bool operator >= ( none_t x, optional<T> const& y ) BOOST_NOEXCEPT
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // header guard
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2026 Andrzej Krzemieński.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
//
|
||||
//
|
||||
// This header provides definitions required by any specialization of
|
||||
// optional<>.
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_SELECT_IMPLEMENTATION_01FEB2026_HPP
|
||||
#define BOOST_OPTIONAL_DETAIL_OPTIONAL_SELECT_IMPLEMENTATION_01FEB2026_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_CONSTEXPR) && \
|
||||
!defined(BOOST_NO_CXX11_REF_QUALIFIERS) && \
|
||||
!defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
|
||||
!defined(BOOST_NO_CXX11_UNRESTRICTED_UNION) && \
|
||||
!defined(BOOST_NO_CXX11_NOEXCEPT) && \
|
||||
!defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
|
||||
# define BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
|
||||
// In C++20 we have `std::construct_at()` which is a constexpr equivalent of
|
||||
// placement-new. We can then make more functions constexpr.
|
||||
// TBD: This additional constexpr-ication is left for the future.
|
||||
# define BOOST_OPTIONAL_CXX20_CONSTEXPR
|
||||
|
||||
#endif //BOOST_OPTIONAL_DETAIL_OPTIONAL_SELECT_IMPLEMENTATION_01FEB2026_HPP
|
||||
@@ -54,7 +54,7 @@ struct swap_selector<true>
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
# define BOOST_OPTIONAL_DETAIL_MOVE(EXPR_) boost::move(EXPR_)
|
||||
# define BOOST_OPTIONAL_DETAIL_MOVE(EXPR_) optional_detail::move_(EXPR_)
|
||||
#else
|
||||
# define BOOST_OPTIONAL_DETAIL_MOVE(EXPR_) EXPR_
|
||||
#endif
|
||||
@@ -63,7 +63,7 @@ template <>
|
||||
struct swap_selector<false>
|
||||
{
|
||||
template <class T>
|
||||
static void optional_swap ( optional<T>& x, optional<T>& y )
|
||||
static void optional_swap ( optional<T>& x, optional<T>& y )
|
||||
//BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && BOOST_NOEXCEPT_EXPR(boost::core::invoke_swap(*x, *y)))
|
||||
{
|
||||
if (x)
|
||||
@@ -91,7 +91,7 @@ struct swap_selector<false>
|
||||
|
||||
} // namespace optional_detail
|
||||
|
||||
#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_CONFIG_RESTORE_OBSOLETE_SWAP_IMPLEMENTATION)
|
||||
#if (!defined BOOST_CONFIG_RESTORE_OBSOLETE_SWAP_IMPLEMENTATION)
|
||||
|
||||
template<class T>
|
||||
struct optional_swap_should_use_default_constructor : boost::false_type {} ;
|
||||
|
||||
@@ -25,10 +25,8 @@ class tc_optional_base : public optional_tag
|
||||
protected:
|
||||
typedef T & reference_type ;
|
||||
typedef T const& reference_const_type ;
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
typedef T && rval_reference_type ;
|
||||
typedef T && reference_type_of_temporary_wrapper ;
|
||||
#endif
|
||||
typedef T * pointer_type ;
|
||||
typedef T const* pointer_const_type ;
|
||||
typedef T const& argument_type ;
|
||||
@@ -51,31 +49,14 @@ class tc_optional_base : public optional_tag
|
||||
|
||||
// tc_optional_base ( tc_optional_base const& ) = default;
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
|
||||
template<class Expr, class PtrExpr>
|
||||
explicit tc_optional_base ( Expr&& expr, PtrExpr const* tag )
|
||||
:
|
||||
m_initialized(false)
|
||||
{
|
||||
construct(boost::forward<Expr>(expr),tag);
|
||||
construct(optional_detail::forward_<Expr>(expr),tag);
|
||||
}
|
||||
|
||||
#else
|
||||
// This is used for both converting and in-place constructions.
|
||||
// Derived classes use the 'tag' to select the appropriate
|
||||
// implementation (the correct 'construct()' overload)
|
||||
template<class Expr>
|
||||
explicit tc_optional_base ( Expr const& expr, Expr const* tag )
|
||||
:
|
||||
m_initialized(false)
|
||||
{
|
||||
construct(expr,tag);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// tc_optional_base& operator= ( tc_optional_base const& ) = default;
|
||||
// ~tc_optional_base() = default;
|
||||
|
||||
@@ -99,7 +80,6 @@ class tc_optional_base : public optional_tag
|
||||
m_initialized = rhs.is_initialized();
|
||||
}
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
// move-assigns from another _convertible_ optional<U> (deep-moves from the rhs value)
|
||||
template<class U>
|
||||
void assign ( optional<U>&& rhs )
|
||||
@@ -109,7 +89,6 @@ class tc_optional_base : public optional_tag
|
||||
m_storage = static_cast<ref_type>(rhs.get());
|
||||
m_initialized = rhs.is_initialized();
|
||||
}
|
||||
#endif
|
||||
|
||||
void assign ( argument_type val )
|
||||
{
|
||||
@@ -120,19 +99,11 @@ class tc_optional_base : public optional_tag
|
||||
|
||||
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
template<class Expr, class ExprPtr>
|
||||
void assign_expr ( Expr&& expr, ExprPtr const* tag )
|
||||
{
|
||||
construct(boost::forward<Expr>(expr),tag);
|
||||
construct(optional_detail::forward_<Expr>(expr),tag);
|
||||
}
|
||||
#else
|
||||
template<class Expr>
|
||||
void assign_expr ( Expr const& expr, Expr const* tag )
|
||||
{
|
||||
construct(expr,tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -162,20 +133,19 @@ class tc_optional_base : public optional_tag
|
||||
}
|
||||
|
||||
|
||||
#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
// Constructs in-place
|
||||
// upon exception *this is always uninitialized
|
||||
template<class... Args>
|
||||
void construct ( in_place_init_t, Args&&... args )
|
||||
{
|
||||
m_storage = value_type( boost::forward<Args>(args)... ) ;
|
||||
m_storage = value_type( optional_detail::forward_<Args>(args)... ) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void emplace_assign ( Args&&... args )
|
||||
{
|
||||
construct(in_place_init, boost::forward<Args>(args)...);
|
||||
construct(in_place_init, optional_detail::forward_<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
@@ -183,7 +153,7 @@ class tc_optional_base : public optional_tag
|
||||
:
|
||||
m_initialized(false)
|
||||
{
|
||||
construct(in_place_init, boost::forward<Args>(args)...);
|
||||
construct(in_place_init, optional_detail::forward_<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
@@ -192,148 +162,11 @@ class tc_optional_base : public optional_tag
|
||||
m_initialized(false)
|
||||
{
|
||||
if ( cond )
|
||||
construct(in_place_init, boost::forward<Args>(args)...);
|
||||
construct(in_place_init, optional_detail::forward_<Args>(args)...);
|
||||
}
|
||||
#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
|
||||
template<class Arg>
|
||||
void construct ( in_place_init_t, Arg&& arg )
|
||||
{
|
||||
m_storage = value_type( boost::forward<Arg>(arg) );
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
void construct ( in_place_init_t )
|
||||
{
|
||||
m_storage = value_type();
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
void emplace_assign ( Arg&& arg )
|
||||
{
|
||||
construct(in_place_init, boost::forward<Arg>(arg)) ;
|
||||
}
|
||||
|
||||
void emplace_assign ()
|
||||
{
|
||||
construct(in_place_init) ;
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
explicit tc_optional_base ( in_place_init_t, Arg&& arg )
|
||||
:
|
||||
m_initialized(false)
|
||||
{
|
||||
construct(in_place_init, boost::forward<Arg>(arg));
|
||||
}
|
||||
|
||||
explicit tc_optional_base ( in_place_init_t )
|
||||
:
|
||||
m_initialized(false), m_storage() {}
|
||||
|
||||
template<class Arg>
|
||||
explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg&& arg )
|
||||
:
|
||||
m_initialized(false)
|
||||
{
|
||||
if ( cond )
|
||||
construct(in_place_init, boost::forward<Arg>(arg));
|
||||
}
|
||||
|
||||
explicit tc_optional_base ( in_place_init_if_t, bool cond )
|
||||
:
|
||||
m_initialized(false)
|
||||
{
|
||||
if ( cond )
|
||||
construct(in_place_init);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<class Arg>
|
||||
void construct ( in_place_init_t, const Arg& arg )
|
||||
{
|
||||
m_storage = value_type( arg );
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
void construct ( in_place_init_t, Arg& arg )
|
||||
{
|
||||
m_storage = value_type( arg );
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
void construct ( in_place_init_t )
|
||||
{
|
||||
m_storage = value_type();
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
void emplace_assign ( const Arg& arg )
|
||||
{
|
||||
construct(in_place_init, arg);
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
void emplace_assign ( Arg& arg )
|
||||
{
|
||||
construct(in_place_init, arg);
|
||||
}
|
||||
|
||||
void emplace_assign ()
|
||||
{
|
||||
construct(in_place_init);
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
explicit tc_optional_base ( in_place_init_t, const Arg& arg )
|
||||
: m_initialized(false)
|
||||
{
|
||||
construct(in_place_init, arg);
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
explicit tc_optional_base ( in_place_init_t, Arg& arg )
|
||||
: m_initialized(false)
|
||||
{
|
||||
construct(in_place_init, arg);
|
||||
}
|
||||
|
||||
explicit tc_optional_base ( in_place_init_t )
|
||||
: m_initialized(false)
|
||||
{
|
||||
construct(in_place_init);
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
explicit tc_optional_base ( in_place_init_if_t, bool cond, const Arg& arg )
|
||||
: m_initialized(false)
|
||||
{
|
||||
if ( cond )
|
||||
construct(in_place_init, arg);
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg& arg )
|
||||
: m_initialized(false)
|
||||
{
|
||||
if ( cond )
|
||||
construct(in_place_init, arg);
|
||||
}
|
||||
|
||||
explicit tc_optional_base ( in_place_init_if_t, bool cond )
|
||||
: m_initialized(false)
|
||||
{
|
||||
if ( cond )
|
||||
construct(in_place_init);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
// Constructs in-place using the given factory
|
||||
template<class Expr>
|
||||
void construct ( Expr&& factory, in_place_factory_base const* )
|
||||
@@ -365,42 +198,8 @@ class tc_optional_base : public optional_tag
|
||||
construct(factory,tag);
|
||||
}
|
||||
|
||||
#else
|
||||
// Constructs in-place using the given factory
|
||||
template<class Expr>
|
||||
void construct ( Expr const& factory, in_place_factory_base const* )
|
||||
{
|
||||
boost_optional_detail::construct<value_type>(factory, boost::addressof(m_storage));
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
// Constructs in-place using the given typed factory
|
||||
template<class Expr>
|
||||
void construct ( Expr const& factory, typed_in_place_factory_base const* )
|
||||
{
|
||||
factory.apply(boost::addressof(m_storage)) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(factory,tag);
|
||||
}
|
||||
|
||||
// Constructs in-place using the given typed factory
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(factory,tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
// Constructs using any expression implicitly convertible to the single argument
|
||||
// of a one-argument T constructor.
|
||||
// Converting constructions of optional<T> from optional<U> uses this function with
|
||||
@@ -408,7 +207,7 @@ class tc_optional_base : public optional_tag
|
||||
template<class Expr>
|
||||
void construct ( Expr&& expr, void const* )
|
||||
{
|
||||
m_storage = value_type(boost::forward<Expr>(expr)) ;
|
||||
m_storage = value_type(optional_detail::forward_<Expr>(expr)) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
@@ -419,31 +218,8 @@ class tc_optional_base : public optional_tag
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr&& expr, void const* )
|
||||
{
|
||||
assign_value( boost::forward<Expr>(expr) );
|
||||
assign_value( optional_detail::forward_<Expr>(expr) );
|
||||
}
|
||||
#else
|
||||
// Constructs using any expression implicitly convertible to the single argument
|
||||
// of a one-argument T constructor.
|
||||
// Converting constructions of optional<T> from optional<U> uses this function with
|
||||
// 'Expr' being of type 'U' and relying on a converting constructor of T from U.
|
||||
template<class Expr>
|
||||
void construct ( Expr const& expr, void const* )
|
||||
{
|
||||
m_storage = value_type(expr) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
// Assigns using a form any expression implicitly convertible to the single argument
|
||||
// of a T's assignment operator.
|
||||
// Converting assignments of optional<T> from optional<U> uses this function with
|
||||
// 'Expr' being of type 'U' and relying on a converting assignment of T from U.
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& expr, void const* )
|
||||
{
|
||||
assign_value(expr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
|
||||
// BCB5.64 (and probably lower versions) workaround.
|
||||
@@ -458,7 +234,7 @@ class tc_optional_base : public optional_tag
|
||||
// For VC<=70 compilers this workaround doesn't work because the compiler issues and error
|
||||
// instead of choosing the wrong overload
|
||||
//
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
|
||||
// Notice that 'Expr' will be optional<T> or optional<U> (but not tc_optional_base<..>)
|
||||
template<class Expr>
|
||||
void construct ( Expr&& expr, optional_tag const* )
|
||||
@@ -467,30 +243,14 @@ class tc_optional_base : public optional_tag
|
||||
{
|
||||
// An exception can be thrown here.
|
||||
// It it happens, THIS will be left uninitialized.
|
||||
m_storage = value_type(boost::move(expr.get())) ;
|
||||
m_storage = value_type(optional_detail::move(expr.get())) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Notice that 'Expr' will be optional<T> or optional<U> (but not tc_optional_base<..>)
|
||||
template<class Expr>
|
||||
void construct ( Expr const& expr, optional_tag const* )
|
||||
{
|
||||
if ( expr.is_initialized() )
|
||||
{
|
||||
// An exception can be thrown here.
|
||||
// It it happens, THIS will be left uninitialized.
|
||||
m_storage = value_type(expr.get()) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
|
||||
|
||||
void assign_value ( argument_type val ) { m_storage = val; }
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
void assign_value ( rval_reference_type val ) { m_storage = static_cast<rval_reference_type>(val); }
|
||||
#endif
|
||||
|
||||
void destroy()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,722 @@
|
||||
// Copyright (C) 2026 Andrzej Krzemieński.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
//
|
||||
//
|
||||
// This header provides definitions required by any specialization of
|
||||
// optional<>.
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
|
||||
#define BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
|
||||
|
||||
//#include <initializer_list>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/invoke_swap.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/optional/bad_optional_access.hpp>
|
||||
|
||||
|
||||
|
||||
// This macro shall be put in the position of a template parameter.
|
||||
// It emulates the requires clause.
|
||||
# define BOOST_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false
|
||||
|
||||
|
||||
# ifdef __cpp_guaranteed_copy_elision
|
||||
# if __cpp_guaranteed_copy_elision
|
||||
# define BOOST_OPTIONAL_CONSTEXPR_COPY
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
template <typename T, typename U>
|
||||
struct fail_hard_on_nonconvertible
|
||||
{
|
||||
static_assert(::std::is_convertible<U&&, T>::value, "The argument must be convertible to T");
|
||||
using type = bool;
|
||||
};
|
||||
|
||||
// Missing C++17 type traits
|
||||
namespace boost { namespace optional_detail {
|
||||
|
||||
template <class...>
|
||||
struct conjunction : ::std::true_type {};
|
||||
|
||||
template <class B1>
|
||||
struct conjunction<B1> : B1 {};
|
||||
|
||||
template <class B1, class... Bn>
|
||||
struct conjunction<B1, Bn...>
|
||||
: ::std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
|
||||
|
||||
}}
|
||||
|
||||
namespace boost { namespace optional_detail {
|
||||
|
||||
// Tag to indicate a special-purpose constructor
|
||||
BOOST_INLINE_VARIABLE constexpr struct trivial_init_t{} trivial_init{};
|
||||
|
||||
|
||||
template <class T>
|
||||
union constexpr_union_storage_t
|
||||
{
|
||||
static_assert(::std::is_trivially_destructible<T>::value, "!!");
|
||||
|
||||
unsigned char dummy_;
|
||||
T value_;
|
||||
|
||||
constexpr constexpr_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
|
||||
|
||||
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
|
||||
// false positive, see https://github.com/boostorg/variant2/issues/55,
|
||||
// https://github.com/boostorg/url/issues/979
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
template <class... Args>
|
||||
constexpr constexpr_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
|
||||
|
||||
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
//~constexpr_union_storage_t() = default; // No need to destroy a trivially-destructible type
|
||||
};
|
||||
|
||||
template <class T>
|
||||
union fallback_union_storage_t
|
||||
{
|
||||
unsigned char dummy_;
|
||||
T value_;
|
||||
|
||||
constexpr fallback_union_storage_t( trivial_init_t ) noexcept : dummy_() {};
|
||||
|
||||
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
|
||||
// false positive, see https://github.com/boostorg/variant2/issues/55,
|
||||
// https://github.com/boostorg/url/issues/979
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
template <class... Args>
|
||||
constexpr fallback_union_storage_t( Args&&... args ) : value_(forward_<Args>(args)...) {}
|
||||
|
||||
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
~fallback_union_storage_t(){} // My owner will destroy the `T` if needed.
|
||||
// Cannot default in a union with nontrivial `T`.
|
||||
};
|
||||
|
||||
|
||||
// `guarded_storage` is a union + a flag indicating if a `T` has been initialized.
|
||||
// this way the destructor knows if it should destroy the `T`.
|
||||
template <class T>
|
||||
struct constexpr_guarded_storage
|
||||
{
|
||||
static_assert(::std::is_trivially_destructible<T>::value, "!!");
|
||||
|
||||
bool init_;
|
||||
constexpr_union_storage_t<T> storage_;
|
||||
|
||||
constexpr constexpr_guarded_storage() noexcept : init_(false), storage_(trivial_init) {};
|
||||
|
||||
explicit constexpr constexpr_guarded_storage(const T& v) : init_(true), storage_(v) {}
|
||||
|
||||
explicit constexpr constexpr_guarded_storage(T&& v) : init_(true), storage_(move_(v)) {}
|
||||
|
||||
template <class... Args> explicit constexpr constexpr_guarded_storage(optional_ns::in_place_init_t, Args&&... args)
|
||||
: init_(true), storage_(forward_<Args>(args)...) {}
|
||||
|
||||
// template <class U, class... Args, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)>
|
||||
// constexpr explicit constexpr_guarded_storage(optional_ns::in_place_init_t, ::std::initializer_list<U> il, Args&&... args)
|
||||
// : init_(true), storage_(il, forward_<Args>(args)...) {}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR void reset () noexcept { init_ = false; }
|
||||
|
||||
//~constexpr_guarded_storage() = default;
|
||||
|
||||
#if (defined(_MSC_VER) && 1910 <= _MSC_VER && _MSC_VER <= 1916)
|
||||
// Workaround for MSVC 14.1x bug where it eagerly tries to define the copy/move operations
|
||||
// these are declared but never defined
|
||||
constexpr_guarded_storage(const constexpr_guarded_storage&);
|
||||
constexpr_guarded_storage(constexpr_guarded_storage&&);
|
||||
constexpr_guarded_storage& operator=(const constexpr_guarded_storage&);
|
||||
constexpr_guarded_storage& operator=(constexpr_guarded_storage&&);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
struct fallback_guarded_storage
|
||||
{
|
||||
bool init_;
|
||||
fallback_union_storage_t<T> storage_;
|
||||
|
||||
constexpr fallback_guarded_storage() noexcept : init_(false), storage_(trivial_init) {};
|
||||
|
||||
explicit constexpr fallback_guarded_storage(const T& v) : init_(true), storage_(v) {}
|
||||
|
||||
explicit constexpr fallback_guarded_storage(T&& v) : init_(true), storage_(move_(v)) {}
|
||||
|
||||
template <class... Args> explicit constexpr fallback_guarded_storage(optional_ns::in_place_init_t, Args&&... args)
|
||||
: init_(true), storage_(forward_<Args>(args)...) {}
|
||||
|
||||
// template <class U, class... Args, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)>
|
||||
// explicit fallback_guarded_storage(optional_ns::in_place_init_t, ::std::initializer_list<U> il, Args&&... args)
|
||||
// : init_(true), storage_(il, forward_<Args>(args)...) {}
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
if (init_)
|
||||
{
|
||||
storage_.value_.T::~T();
|
||||
init_ = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
~fallback_guarded_storage() { if (init_) storage_.value_.T::~T(); }
|
||||
|
||||
#if (defined(_MSC_VER) && 1910 <= _MSC_VER && _MSC_VER <= 1916)
|
||||
// Workaround for MSVC 14.1x bug where it eagerly tries to define the copy/move operations
|
||||
// These are declared but never defined
|
||||
fallback_guarded_storage(const fallback_guarded_storage&);
|
||||
fallback_guarded_storage(fallback_guarded_storage&&);
|
||||
fallback_guarded_storage& operator=(const fallback_guarded_storage&);
|
||||
fallback_guarded_storage& operator=(fallback_guarded_storage&&);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
using guarded_storage = typename ::std::conditional<
|
||||
::std::is_trivially_destructible<T>::value, // if possible
|
||||
constexpr_guarded_storage<typename ::std::remove_const<T>::type>, // use storage with trivial destructor
|
||||
fallback_guarded_storage<typename ::std::remove_const<T>::type>
|
||||
>::type;
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <class T>
|
||||
class optional : public optional_detail::optional_tag
|
||||
{
|
||||
using storage_t = optional_detail::guarded_storage<T>;
|
||||
storage_t storage;
|
||||
static_assert( !::std::is_same<typename std::decay<T>::type, none_t>::value, "optional<none_t> is illegal" );
|
||||
static_assert( !::std::is_same<typename std::decay<T>::type, in_place_init_t>::value, "optional<in_place_init_t> is illegal" );
|
||||
static_assert( !::std::is_same<typename std::decay<T>::type, in_place_init_if_t>::value, "optional<in_place_init_if_t> is illegal" );
|
||||
|
||||
BOOST_CXX14_CONSTEXPR typename ::std::remove_const<T>::type* dataptr() { return ::boost::addressof(storage.storage_.value_); }
|
||||
constexpr const T* dataptr() const { return ::boost::addressof(storage.storage_.value_); }
|
||||
|
||||
constexpr const T& contained_val() const& { return storage.storage_.value_; }
|
||||
BOOST_CXX14_CONSTEXPR T&& contained_val() && { return optional_detail::move_(storage.storage_.value_); }
|
||||
BOOST_CXX14_CONSTEXPR T& contained_val() & { return storage.storage_.value_; }
|
||||
|
||||
template <typename... Args>
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR void initialize(Args&&... args)
|
||||
{
|
||||
BOOST_ASSERT(!storage.init_);
|
||||
::new (static_cast<void*>(dataptr())) T(optional_detail::forward_<Args>(args)...);
|
||||
storage.init_ = true;
|
||||
}
|
||||
|
||||
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
|
||||
// The conditional initialization of storage needs to employ a factory
|
||||
// function, so that we can utilize the guaranteed copy elision on the
|
||||
// return type.
|
||||
// an alternative -- using a conditional operator in the initializer --
|
||||
// does not work in MSVC 14.2 and 14.3.
|
||||
template <typename... U>
|
||||
static constexpr storage_t conditional_storage_from_values(bool cond, U&&... v)
|
||||
{
|
||||
if (cond)
|
||||
return storage_t(in_place_init, optional_detail::forward_<U>(v)...);
|
||||
else
|
||||
return storage_t();
|
||||
}
|
||||
|
||||
template <typename OU>
|
||||
static constexpr storage_t conditional_storage_from_optional(OU&& ou)
|
||||
{
|
||||
if (ou.has_value())
|
||||
return storage_t(in_place_init, *optional_detail::forward_<OU>(ou));
|
||||
else
|
||||
return storage_t();
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using unqualified_value_type = typename ::std::remove_const<T>::type;
|
||||
|
||||
using reference_type = T&;
|
||||
using reference_const_type = T const&;
|
||||
using argument_type = T const&;
|
||||
using rval_reference_type = T&&;
|
||||
using reference_type_of_temporary_wrapper = T&&;
|
||||
using pointer_type = T*;
|
||||
using pointer_const_type = T const*;
|
||||
|
||||
|
||||
constexpr bool is_initialized() const noexcept { return storage.init_; }
|
||||
|
||||
constexpr optional() noexcept : storage() {};
|
||||
constexpr optional(none_t) noexcept : storage() {};
|
||||
|
||||
constexpr optional(const T& v) : storage(v) {}
|
||||
constexpr optional(T&& v) : storage(optional_detail::move_(v)) {}
|
||||
|
||||
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
|
||||
constexpr optional(bool cond, const T& v)
|
||||
: storage(conditional_storage_from_values(cond, v))
|
||||
{}
|
||||
|
||||
constexpr optional(bool cond, T&& v)
|
||||
: storage(conditional_storage_from_values(cond, optional_detail::move_(v)))
|
||||
{}
|
||||
|
||||
constexpr optional(const optional& rhs)
|
||||
: storage(conditional_storage_from_optional(rhs))
|
||||
{}
|
||||
|
||||
constexpr optional(optional&& rhs)
|
||||
noexcept(::std::is_nothrow_move_constructible<T>::value)
|
||||
: storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
|
||||
{}
|
||||
|
||||
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)>
|
||||
constexpr explicit optional(optional<U> const& rhs)
|
||||
: storage(conditional_storage_from_optional(rhs))
|
||||
{}
|
||||
|
||||
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
|
||||
constexpr explicit optional(optional<U> && rhs)
|
||||
: storage(conditional_storage_from_optional(optional_detail::move_(rhs)))
|
||||
{}
|
||||
|
||||
template <typename... Args>
|
||||
constexpr explicit optional( in_place_init_if_t, bool cond, Args&&... args )
|
||||
: storage(conditional_storage_from_values(cond, optional_detail::forward_<Args>(args)...))
|
||||
{}
|
||||
#else
|
||||
optional(bool cond, const T& v)
|
||||
: storage()
|
||||
{
|
||||
if (cond)
|
||||
initialize(v);
|
||||
}
|
||||
|
||||
optional(bool cond, T&& v)
|
||||
: storage()
|
||||
{
|
||||
if (cond)
|
||||
initialize(optional_detail::move_(v));
|
||||
}
|
||||
|
||||
optional(const optional& rhs)
|
||||
: storage()
|
||||
{
|
||||
if (rhs.is_initialized())
|
||||
initialize(*rhs);
|
||||
}
|
||||
|
||||
optional(optional&& rhs)
|
||||
noexcept(::std::is_nothrow_move_constructible<T>::value)
|
||||
: storage()
|
||||
{
|
||||
if (rhs.is_initialized())
|
||||
initialize(*optional_detail::move_(rhs));
|
||||
}
|
||||
|
||||
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U const&>)>
|
||||
explicit optional(optional<U> const& rhs)
|
||||
: storage()
|
||||
{
|
||||
if (rhs.is_initialized())
|
||||
initialize(*rhs);
|
||||
}
|
||||
|
||||
template <typename U, BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>)>
|
||||
explicit optional(optional<U> && rhs)
|
||||
: storage()
|
||||
{
|
||||
if (rhs.is_initialized())
|
||||
initialize(*optional_detail::move_(rhs));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
explicit optional( in_place_init_if_t, bool cond, Args&&... args )
|
||||
: storage()
|
||||
{
|
||||
if (cond)
|
||||
initialize(optional_detail::forward_<Args>(args)...);
|
||||
}
|
||||
#endif // BOOST_OPTIONAL_CONSTEXPR_COPY
|
||||
|
||||
template <typename FT,
|
||||
BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<FT>)>
|
||||
/*non-constexpr (deprecated)*/
|
||||
explicit optional (FT&& factory)
|
||||
: storage()
|
||||
{
|
||||
factory.apply(this->dataptr());
|
||||
storage.init_ = true ;
|
||||
}
|
||||
|
||||
template <typename FT,
|
||||
BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<FT>)>
|
||||
/*non-constexpr (deprecated)*/
|
||||
explicit optional (FT&& factory)
|
||||
: storage()
|
||||
{
|
||||
boost_optional_detail::construct<value_type>(factory, this->dataptr());
|
||||
storage.init_ = true;
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U&&>),
|
||||
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_typed_in_place_factory<U>),
|
||||
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_in_place_factory<U>)>
|
||||
constexpr explicit optional(U&& v)
|
||||
: storage(optional_ns::in_place_init, optional_detail::forward_<U>(v))
|
||||
{}
|
||||
|
||||
template <typename... Args>
|
||||
constexpr explicit optional( in_place_init_t, Args&&... args )
|
||||
: storage(in_place_init, optional_detail::forward_<Args>(args)...)
|
||||
{}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR operator optional<T&>() & noexcept
|
||||
{
|
||||
return this->has_value() ? optional<T&>(**this) : optional<T&>();
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR operator optional<const T&>() const& noexcept
|
||||
{
|
||||
return this->has_value() ? optional<const T&>(**this) : optional<const T&>();
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR operator optional<T&>() && noexcept = delete;
|
||||
BOOST_CONSTEXPR operator optional<const T&>() const&& noexcept = delete;
|
||||
|
||||
|
||||
BOOST_CXX14_CONSTEXPR void reset() noexcept
|
||||
{
|
||||
storage.reset();
|
||||
}
|
||||
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR void reset(const T& v)
|
||||
{
|
||||
*this = v;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR void emplace(Args&&... args)
|
||||
{
|
||||
reset();
|
||||
// <-- now we are not containing a value
|
||||
initialize(optional_detail::forward_<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
BOOST_CXX14_CONSTEXPR optional& operator=(none_t) noexcept
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(const optional& rhs)
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
if (rhs.has_value())
|
||||
**this = *rhs;
|
||||
else
|
||||
reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rhs.has_value())
|
||||
initialize(*rhs);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(optional&& rhs)
|
||||
noexcept(::std::is_nothrow_move_assignable<T>::value && ::std::is_nothrow_move_constructible<T>::value)
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
if (rhs.has_value())
|
||||
**this = *optional_detail::move_(rhs);
|
||||
else
|
||||
reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rhs.has_value())
|
||||
initialize(*optional_detail::move_(rhs) );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(const optional<U>& rhs)
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
if (rhs.has_value())
|
||||
**this = *rhs;
|
||||
else
|
||||
reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rhs.has_value())
|
||||
initialize(*rhs);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(optional<U>&& rhs)
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
if (rhs.has_value())
|
||||
**this = *optional_detail::move_(rhs);
|
||||
else
|
||||
reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rhs.has_value())
|
||||
initialize(*optional_detail::move_(rhs));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U = typename ::std::remove_cv<T>::type,
|
||||
BOOST_OPTIONAL_REQUIRES(!::std::is_same<typename ::std::decay<U>::type, optional>),
|
||||
BOOST_OPTIONAL_REQUIRES(!optional_detail::conjunction<::std::is_scalar<T>, ::std::is_same<T, BOOST_OPTIONAL_DECAY(U)>>),
|
||||
BOOST_OPTIONAL_REQUIRES(::std::is_constructible<T, U>),
|
||||
BOOST_OPTIONAL_REQUIRES(::std::is_assignable<T&, U>),
|
||||
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_typed_in_place_factory<U>),
|
||||
BOOST_OPTIONAL_REQUIRES(!optional_detail::is_in_place_factory<U>)
|
||||
>
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR optional& operator=(U&& v)
|
||||
{
|
||||
if (is_initialized())
|
||||
contained_val() = optional_detail::forward_<U>(v);
|
||||
else
|
||||
initialize(optional_detail::forward_<U>(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_in_place_factory<F>)>
|
||||
/*non-constexpr (deprecated)*/
|
||||
optional& operator=(F&& factory)
|
||||
{
|
||||
reset();
|
||||
boost_optional_detail::construct<value_type>(factory, this->dataptr());
|
||||
storage.init_ = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class F, BOOST_OPTIONAL_REQUIRES(optional_detail::is_typed_in_place_factory<F>)>
|
||||
/*non-constexpr (deprecated)*/
|
||||
optional& operator=(F&& factory)
|
||||
{
|
||||
reset();
|
||||
factory.apply(this->dataptr());
|
||||
storage.init_ = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR
|
||||
void swap(optional& rhs)
|
||||
noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*rhs, *rhs)))
|
||||
{
|
||||
if (is_initialized())
|
||||
{
|
||||
if (rhs.is_initialized())
|
||||
boost::core::invoke_swap(contained_val(), rhs.contained_val());
|
||||
else
|
||||
{ rhs.initialize(optional_detail::move_(*this).contained_val()); reset(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rhs.is_initialized())
|
||||
{ initialize(optional_detail::move_(rhs).contained_val()); rhs.reset(); }
|
||||
}
|
||||
}
|
||||
|
||||
~optional() = default; // The destructor in `storage`, based on the specialization
|
||||
// will be trivial or not.
|
||||
|
||||
constexpr bool has_value() const noexcept { return this->is_initialized(); }
|
||||
constexpr explicit operator bool() const noexcept { return this->is_initialized(); }
|
||||
|
||||
constexpr reference_const_type get() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(this->is_initialized(), this->contained_val()); }
|
||||
BOOST_CXX14_CONSTEXPR reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return this->contained_val(); }
|
||||
|
||||
//BOOST_DEPRECATED("use `value_or(v)` instead")
|
||||
reference_const_type get_value_or (reference_const_type v) const { return this->is_initialized() ? this->contained_val() : v; }
|
||||
|
||||
//BOOST_DEPRECATED("use `value_or(v)` instead")
|
||||
reference_type get_value_or (reference_type v) { return this->is_initialized() ? this->contained_val() : v; }
|
||||
|
||||
pointer_const_type get_ptr() const { return is_initialized() ? dataptr() : nullptr; }
|
||||
pointer_type get_ptr() { return is_initialized() ? dataptr() : nullptr; }
|
||||
|
||||
constexpr reference_const_type operator*() const& { return this->get(); }
|
||||
BOOST_CXX14_CONSTEXPR reference_type operator*() & { return this->get(); }
|
||||
BOOST_CXX14_CONSTEXPR reference_type_of_temporary_wrapper operator*() && { return optional_detail::move_(this->get()); }
|
||||
|
||||
constexpr pointer_const_type operator->() const { return BOOST_OPTIONAL_ASSERTED_EXPRESSION(this->is_initialized(), this->dataptr()); }
|
||||
BOOST_CXX14_CONSTEXPR pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->dataptr(); }
|
||||
|
||||
constexpr reference_const_type value() const&
|
||||
{
|
||||
return this->is_initialized() ? this->get() : (boost::throw_exception(boost::bad_optional_access()), this->get());
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR reference_type value() &
|
||||
{
|
||||
if (this->is_initialized())
|
||||
return this->get();
|
||||
else
|
||||
boost::throw_exception(boost::bad_optional_access());
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR reference_type_of_temporary_wrapper value() &&
|
||||
{
|
||||
if (this->is_initialized())
|
||||
return optional_detail::move_(this->get());
|
||||
else
|
||||
boost::throw_exception(boost::bad_optional_access());
|
||||
}
|
||||
|
||||
template <class U = typename ::std::remove_cv<T>::type,
|
||||
typename fail_hard_on_nonconvertible<T, U>::type = true>
|
||||
constexpr value_type value_or(U&& v) const&
|
||||
{
|
||||
return this->is_initialized() ? get() : T(optional_detail::forward_<U>(v));
|
||||
}
|
||||
|
||||
template <class U = typename ::std::remove_cv<T>::type>
|
||||
BOOST_CXX14_CONSTEXPR value_type value_or(U&& v) &&
|
||||
{
|
||||
if (this->is_initialized())
|
||||
return optional_detail::move_(get());
|
||||
else
|
||||
return optional_detail::forward_<U>(v);
|
||||
}
|
||||
|
||||
template <typename F,
|
||||
typename fail_hard_on_nonconvertible<T, decltype(optional_detail::declval_<F>()())>::type = true>
|
||||
constexpr value_type value_or_eval(F f) const&
|
||||
{
|
||||
return this->is_initialized() ? get() : value_type(f());
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
BOOST_CXX14_CONSTEXPR value_type value_or_eval ( F f ) &&
|
||||
{
|
||||
if (this->is_initialized())
|
||||
return optional_detail::move_(get());
|
||||
else
|
||||
return f();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_of<F, reference_type>::type>
|
||||
map(F f) &
|
||||
{
|
||||
if (this->has_value())
|
||||
return f(get());
|
||||
else
|
||||
return none;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
constexpr optional<typename optional_detail::result_of<F, reference_const_type>::type>
|
||||
map(F f) const&
|
||||
{
|
||||
return this->has_value() ?
|
||||
f(get()) :
|
||||
optional<typename optional_detail::result_of<F, reference_const_type>::type>();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_of<F, reference_type_of_temporary_wrapper>::type>
|
||||
map(F f) &&
|
||||
{
|
||||
if (this->has_value())
|
||||
return f(optional_detail::move_(this->get()));
|
||||
else
|
||||
return none;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_value_type<F, reference_type>::type>
|
||||
flat_map(F f) &
|
||||
{
|
||||
if (this->has_value())
|
||||
return f(get());
|
||||
else
|
||||
return none;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
constexpr optional<typename optional_detail::result_value_type<F, reference_const_type>::type>
|
||||
flat_map(F f) const&
|
||||
{
|
||||
return this->has_value() ?
|
||||
f(get()) :
|
||||
optional<typename optional_detail::result_value_type<F, reference_const_type>::type>();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
BOOST_CXX14_CONSTEXPR optional<typename optional_detail::result_value_type<F, reference_type_of_temporary_wrapper>::type>
|
||||
flat_map(F f) &&
|
||||
{
|
||||
if (this->has_value())
|
||||
return f(optional_detail::move_(get()));
|
||||
else
|
||||
return none;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
BOOST_OPTIONAL_CXX20_CONSTEXPR
|
||||
void swap(optional<T>& lhs, optional<T>& rhs)
|
||||
noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*lhs, *rhs)))
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BOOST_OPTIONAL_DETAIL_UNION_OPTIONAL_01FEB2026_HPP
|
||||
+170
-781
File diff suppressed because it is too large
Load Diff
@@ -17,25 +17,35 @@
|
||||
#define BOOST_OPTIONAL_OPTIONAL_FWD_FLC_19NOV2002_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/invoke_swap.hpp>
|
||||
#include <boost/optional/detail/optional_select_implementation.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
template<class T> class optional ;
|
||||
|
||||
// This forward is needed to refer to namespace scope swap from the member swap
|
||||
template<class T> void swap ( optional<T>& , optional<T>& ) ;
|
||||
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
template<class T> BOOST_OPTIONAL_CXX20_CONSTEXPR void swap ( optional<T>& lhs, optional<T>& rhs )
|
||||
noexcept(::std::is_nothrow_move_constructible<T>::value && noexcept(boost::core::invoke_swap(*lhs, *rhs)));
|
||||
#else
|
||||
template<class T> void swap ( optional<T>& , optional<T>& ) ;
|
||||
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
|
||||
|
||||
template<class T> struct optional_swap_should_use_default_constructor ;
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_CONFIG_DONT_SPECIALIZE_OPTIONAL_REFS
|
||||
|
||||
template<class T> class optional<T&> ;
|
||||
template<class T> class optional<T&> ;
|
||||
|
||||
template<class T> void swap ( optional<T&>& , optional<T&>& ) BOOST_NOEXCEPT;
|
||||
template<class T> BOOST_CXX14_CONSTEXPR void swap ( optional<T&>& , optional<T&>& ) BOOST_NOEXCEPT;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -63,11 +63,7 @@ operator>>(std::basic_istream<CharType, CharTrait>& in, optional<T>& v)
|
||||
{
|
||||
T x;
|
||||
in >> x;
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
v = boost::move(x);
|
||||
#else
|
||||
v = x;
|
||||
#endif
|
||||
v = optional_detail::move_(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1
-1
@@ -13,5 +13,5 @@
|
||||
"Fernando Cacciola <fernando_cacciola -at- ciudad.com.ar>",
|
||||
"Andrzej Krzemienski <akrzemi1 -at- gmail.com>"
|
||||
],
|
||||
"cxxstd": "03"
|
||||
"cxxstd": "11"
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
|
||||
|
||||
if(HAVE_BOOST_TEST)
|
||||
|
||||
boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::optional Boost::core Boost::bind Boost::mpl Boost::tuple)
|
||||
boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::optional Boost::core Boost::bind Boost::tuple Boost::utility)
|
||||
|
||||
endif()
|
||||
|
||||
+25
-3
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Copyright (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
# Copyright (C) 2014 - 2017 Andrzej Krzemienski
|
||||
# Copyright (C) 2024 Alexander Grund
|
||||
#
|
||||
# Use, modification, and distribution is subject to the Boost Software
|
||||
# License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -13,12 +14,31 @@
|
||||
# akrzemi1@gmail.com
|
||||
#
|
||||
|
||||
import config : requires ;
|
||||
import testing ;
|
||||
|
||||
run optional_test.cpp ;
|
||||
project
|
||||
: requirements
|
||||
<library>/boost/optional//boost_optional
|
||||
[ requires
|
||||
cxx11_decltype
|
||||
cxx11_defaulted_functions
|
||||
cxx11_defaulted_moves
|
||||
cxx11_deleted_functions
|
||||
cxx11_explicit_conversion_operators
|
||||
# cxx11_noexcept
|
||||
cxx11_rvalue_references
|
||||
cxx11_variadic_templates
|
||||
]
|
||||
;
|
||||
|
||||
|
||||
run optional_test.cpp : : : <library>/boost/bind//boost_bind ;
|
||||
run optional_test_assign.cpp ;
|
||||
run optional_test_swap.cpp ;
|
||||
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_convert_from_T.cpp ;
|
||||
run optional_test_convert_assign.cpp ;
|
||||
@@ -27,7 +47,8 @@ run optional_test_make_optional.cpp ;
|
||||
run optional_test_flat_map.cpp ;
|
||||
run optional_test_hash.cpp ;
|
||||
run optional_test_map.cpp ;
|
||||
run optional_test_tie.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 ;
|
||||
@@ -42,7 +63,7 @@ run optional_test_inplace_factory.cpp ;
|
||||
run optional_test_io.cpp ;
|
||||
run optional_test_move.cpp ;
|
||||
run optional_test_noexcept_move.cpp ;
|
||||
run optional_test_equals_none.cpp ;
|
||||
run optional_test_cmp_none.cpp ;
|
||||
run optional_test_value_access.cpp ;
|
||||
run optional_test_emplace.cpp ;
|
||||
run optional_test_minimum_requirements.cpp ;
|
||||
@@ -59,6 +80,7 @@ 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 ;
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin
|
||||
#endif
|
||||
#include "boost/mpl/bool.hpp"
|
||||
#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_
|
||||
|
||||
#include "boost/optional/optional.hpp"
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2021 Andrzej Krzemienski.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/lib/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
|
||||
template <typename U>
|
||||
struct wrapper {};
|
||||
|
||||
template <typename /*Tag*/, typename U>
|
||||
int get(wrapper<U> const&) { return 0; }
|
||||
|
||||
#include "boost/optional/optional.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct any_type_in_boost_namespace {};
|
||||
}
|
||||
|
||||
class tag; // user-defined tag
|
||||
|
||||
int main()
|
||||
{
|
||||
// the following tests if boost::get for optional<> does
|
||||
// not interfere with the global get
|
||||
return get<tag>(wrapper<boost::any_type_in_boost_namespace>());
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright (C) 2014 Andrzej Krzemienski.
|
||||
// Copyright (C) 2024 Alexander Grund
|
||||
//
|
||||
// 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"
|
||||
|
||||
#ifdef BOOST_BORLANDC
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include "boost/none.hpp"
|
||||
|
||||
|
||||
struct SemiRegular // no operator==
|
||||
{
|
||||
private: void operator==(SemiRegular const&) const {}
|
||||
private: void operator!=(SemiRegular const&) const {}
|
||||
};
|
||||
|
||||
void test_equal_to_none_of_noncomparable_T()
|
||||
{
|
||||
boost::optional<SemiRegular> i = SemiRegular();
|
||||
boost::optional<SemiRegular> o;
|
||||
|
||||
BOOST_TEST(i != boost::none);
|
||||
BOOST_TEST(boost::none != i);
|
||||
BOOST_TEST(o == boost::none);
|
||||
BOOST_TEST(boost::none == o);
|
||||
}
|
||||
|
||||
void test_comparison_to_none()
|
||||
{
|
||||
using boost::none;
|
||||
boost::optional<SemiRegular> i = SemiRegular();
|
||||
// the default ordering of optional<size_t> is{ boost::none, 0, 1, 2, ... }
|
||||
// Hence boost::none < i for any engaged i
|
||||
// and all others operators ( ==, !=, <, <=, >, >= ) follow
|
||||
|
||||
BOOST_TEST(!(i == none));
|
||||
BOOST_TEST(i != none);
|
||||
BOOST_TEST(!(i < none));
|
||||
BOOST_TEST(!(i <= none));
|
||||
BOOST_TEST(i > none);
|
||||
BOOST_TEST(i >= none);
|
||||
// Comparison is symmetric
|
||||
BOOST_TEST(!(none == i));
|
||||
BOOST_TEST(none != i);
|
||||
BOOST_TEST(none < i);
|
||||
BOOST_TEST(none <= i);
|
||||
BOOST_TEST(!(none > i));
|
||||
BOOST_TEST(!(none >= i));
|
||||
|
||||
// An un-engaged optional is always equal to none
|
||||
boost::optional<SemiRegular> o;
|
||||
BOOST_TEST(o == none);
|
||||
BOOST_TEST(!(o != none));
|
||||
BOOST_TEST(!(o < none));
|
||||
BOOST_TEST(o <= none);
|
||||
BOOST_TEST(!(o > none));
|
||||
BOOST_TEST(o >= none);
|
||||
// Comparison is symmetric
|
||||
BOOST_TEST(none == o);
|
||||
BOOST_TEST(!(none != o));
|
||||
BOOST_TEST(!(none < o));
|
||||
BOOST_TEST(none <= o);
|
||||
BOOST_TEST(!(none > o));
|
||||
BOOST_TEST(none >= o);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_equal_to_none_of_noncomparable_T();
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright (C) 2026, Andrzej Krzemieński.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/lib/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
|
||||
#include "boost/optional.hpp"
|
||||
|
||||
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
|
||||
struct Record
|
||||
{
|
||||
int i;
|
||||
constexpr explicit Record(int i) : i(i) {}
|
||||
constexpr int operator()() const { return i; }
|
||||
};
|
||||
|
||||
struct Guard
|
||||
{
|
||||
int i;
|
||||
constexpr explicit Guard(int i) : i(i) {}
|
||||
Guard(Guard&&) = delete;
|
||||
};
|
||||
|
||||
static_assert(boost::none == boost::none, "");
|
||||
static_assert(!(boost::none != boost::none), "");
|
||||
|
||||
namespace test_int
|
||||
{
|
||||
constexpr boost::optional<int> oN;
|
||||
static_assert(!oN, "");
|
||||
static_assert(oN == boost::none, "");
|
||||
static_assert(oN <= boost::none, "");
|
||||
static_assert(!(oN != boost::none), "");
|
||||
static_assert(oN == oN, "");
|
||||
static_assert(!oN.has_value(), "");
|
||||
static_assert(oN.value_or({}) == 0, "");
|
||||
static_assert(oN.value_or(0) == 0, "");
|
||||
static_assert(oN.value_or_eval(Record(9)) == 9, "");
|
||||
|
||||
constexpr boost::optional<int> o1 (1);
|
||||
constexpr boost::optional<int> o2 {2};
|
||||
|
||||
static_assert(o1, "");
|
||||
static_assert(o1.has_value(), "");
|
||||
static_assert(o1 != boost::none, "");
|
||||
static_assert(o1 != oN, "");
|
||||
static_assert(o1 > oN, "");
|
||||
static_assert(o1 >= oN, "");
|
||||
static_assert(*o1 == 1, "");
|
||||
static_assert(o1.value() == 1, "");
|
||||
static_assert(o1.value_or(0) == 1, "");
|
||||
static_assert(o1.value_or({}) == 1, "");
|
||||
static_assert(o1.value_or_eval(Record(9)) == 1, "");
|
||||
static_assert(o1 == 1, "");
|
||||
static_assert(o2, "");
|
||||
static_assert(o2 != o1, "");
|
||||
static_assert(o2 > o1, "");
|
||||
|
||||
#ifdef BOOST_OPTIONAL_CONSTEXPR_COPY
|
||||
constexpr boost::optional<int> oNc = oN;
|
||||
constexpr boost::optional<int> oNd = boost::none;
|
||||
constexpr boost::optional<int> oNe = {};
|
||||
static_assert(oNc == oN, "");
|
||||
static_assert(oNd == oN, "");
|
||||
static_assert(oNe == oN, "");
|
||||
|
||||
constexpr bool test_reset() {
|
||||
boost::optional<int> o = 1;
|
||||
assert(o);
|
||||
o = boost::none;
|
||||
assert(!o);
|
||||
return o == boost::none;
|
||||
}
|
||||
|
||||
static_assert(test_reset(), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace test_record
|
||||
{
|
||||
constexpr boost::optional<Record> rN (boost::none);
|
||||
constexpr boost::optional<Record> r1 (Record(1));
|
||||
constexpr boost::optional<Record> r2 (boost::in_place_init, 2);
|
||||
|
||||
static_assert(!rN, "");
|
||||
static_assert(rN == boost::none, "");
|
||||
static_assert(r1, "");
|
||||
static_assert(r1 != boost::none, "");
|
||||
static_assert(r2, "");
|
||||
static_assert(rN.value_or(Record(9)).i == 9, "");
|
||||
static_assert(r1->i == 1, "");
|
||||
static_assert(r2.value().i == 2, "");
|
||||
}
|
||||
|
||||
namespace test_guard
|
||||
{
|
||||
constexpr boost::optional<Guard> g1 {boost::in_place_init, 1};
|
||||
constexpr boost::optional<Guard> gNa {boost::none};
|
||||
constexpr boost::optional<Guard> gNb;
|
||||
|
||||
static_assert(g1, "");
|
||||
static_assert(!!g1, "");
|
||||
static_assert(g1 != boost::none, "");
|
||||
static_assert(!(g1 == boost::none), "");
|
||||
static_assert(g1.has_value(), "");
|
||||
|
||||
static_assert(!gNa, "");
|
||||
static_assert(!gNa.has_value(), "");
|
||||
static_assert(gNa == boost::none, "");
|
||||
static_assert(!(gNa != boost::none), "");
|
||||
|
||||
static_assert(!gNb, "");
|
||||
static_assert(!gNb.has_value(), "");
|
||||
static_assert(gNb == boost::none, "");
|
||||
static_assert(!(gNb != boost::none), "");
|
||||
}
|
||||
|
||||
namespace test_optional_ref
|
||||
{
|
||||
constexpr int gi = 9;
|
||||
constexpr boost::optional<const int&> iref = gi;
|
||||
static_assert(iref, "");
|
||||
static_assert(*iref == 9, "");
|
||||
}
|
||||
|
||||
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
@@ -55,5 +55,6 @@ int main()
|
||||
{
|
||||
// Invokes boost::optional copy constructor. Should not invoke wrapper constructor from U.
|
||||
boost::optional< wrapper< int > > res = foo();
|
||||
(void)res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include "boost/none.hpp"
|
||||
#include "boost/type_traits/is_assignable.hpp"
|
||||
|
||||
//#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR
|
||||
|
||||
@@ -25,8 +26,7 @@ struct implicit_bool_conv
|
||||
|
||||
struct explicit_bool_conv
|
||||
{
|
||||
bool operator!() const BOOST_NOEXCEPT { return false; }
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
explicit operator bool() const BOOST_NOEXCEPT { return true; }
|
||||
};
|
||||
|
||||
template <typename To, typename From>
|
||||
@@ -41,9 +41,9 @@ void test_no_bad_assignment()
|
||||
{
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && !BOOST_WORKAROUND(BOOST_MSVC, < 1800)
|
||||
// this means that type trait `boost::is_assignable` works.
|
||||
BOOST_STATIC_ASSERT((boost::is_assignable<optional<bool>&, bool>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_assignable<optional<bool>&, implicit_bool_conv>::value));
|
||||
BOOST_STATIC_ASSERT((! boost::is_assignable<optional<bool>&, explicit_bool_conv>::value));
|
||||
static_assert((boost::is_assignable<optional<bool>&, bool>::value), "ERROR");
|
||||
static_assert((boost::is_assignable<optional<bool>&, implicit_bool_conv>::value), "ERROR");
|
||||
static_assert((! boost::is_assignable<optional<bool>&, explicit_bool_conv>::value), "ERROR");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,14 @@ struct superconv
|
||||
{
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
superconv(T&&) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
|
||||
superconv(T&&) { static_assert(sizeof(T) == 0, "ERROR"); }
|
||||
#else
|
||||
template <typename T>
|
||||
superconv(const T&) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
|
||||
superconv(const T&) { static_assert(sizeof(T) == 0, "ERROR"); }
|
||||
template <typename T>
|
||||
superconv( T&) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
|
||||
superconv( T&) { static_assert(sizeof(T) == 0, "ERROR"); }
|
||||
#endif
|
||||
|
||||
|
||||
superconv() {}
|
||||
};
|
||||
|
||||
@@ -45,6 +45,8 @@ 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
|
||||
}
|
||||
|
||||
@@ -52,19 +54,19 @@ void test_optional_optional_T()
|
||||
{
|
||||
optional<int> oi1 (1), oiN;
|
||||
optional< optional<int> > ooi1 (oi1), ooiN(oiN);
|
||||
|
||||
|
||||
BOOST_TEST(ooi1);
|
||||
BOOST_TEST(*ooi1);
|
||||
BOOST_TEST_EQ(**ooi1, 1);
|
||||
|
||||
|
||||
BOOST_TEST(ooiN);
|
||||
BOOST_TEST(!*ooiN);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_optional_optional_T();
|
||||
test_optional_of_superconverting_T();
|
||||
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright (C) 2014 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"
|
||||
|
||||
#ifdef BOOST_BORLANDC
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include "boost/none.hpp"
|
||||
|
||||
|
||||
struct SemiRegular // no operator==
|
||||
{
|
||||
private: void operator==(SemiRegular const&) const {}
|
||||
private: void operator!=(SemiRegular const&) const {}
|
||||
};
|
||||
|
||||
void test_equal_to_none_of_noncomparable_T()
|
||||
{
|
||||
boost::optional<SemiRegular> i = SemiRegular();
|
||||
boost::optional<SemiRegular> o;
|
||||
|
||||
BOOST_TEST(i != boost::none);
|
||||
BOOST_TEST(boost::none != i);
|
||||
BOOST_TEST(o == boost::none);
|
||||
BOOST_TEST(boost::none == o);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_equal_to_none_of_noncomparable_T();
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -43,9 +43,9 @@ struct DeletedDefault
|
||||
};
|
||||
|
||||
namespace boost { namespace optional_config {
|
||||
|
||||
|
||||
template <> struct optional_uses_direct_storage_for<CustomizedTrivial> : boost::true_type {};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
struct CustDtor
|
||||
@@ -78,47 +78,47 @@ void test_type_traits()
|
||||
// this only tests if type traits are implemented correctly
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<int> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<double> ));
|
||||
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<CustomizedTrivial> ));
|
||||
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<PrivDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<NoDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, CustDefault> > ));
|
||||
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustDtor> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustAssign> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustMove> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, CustMove> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<int> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<double> ));
|
||||
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<int> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<double> ));
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<Empty> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<Aggregate<Empty, int>, double> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Empty> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<int, double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<Aggregate<Empty, int>, double> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<PrivDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<NoDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<CustDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<int, CustDefault> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<DeletedDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<int, DeletedDefault> > ));
|
||||
#endif
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Empty> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Aggregate<int, double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Aggregate<Aggregate<Empty, int>, double> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<PrivDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<NoDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<CustDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Aggregate<int, CustDefault> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<DeletedDefault> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Aggregate<int, DeletedDefault> > ));
|
||||
#endif
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<DeletedDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, DeletedDefault> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<CustDtor> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<CustAssign> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<CustMove> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<int, CustMove> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<CustDtor> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<CustAssign> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<CustMove> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<Aggregate<int, CustMove> > ));
|
||||
}
|
||||
|
||||
void test_trivial_copyability()
|
||||
@@ -127,16 +127,16 @@ void test_trivial_copyability()
|
||||
BOOST_TEST_TRAIT_TRUE((boost::is_base_of<boost::optional_detail::tc_optional_base<double>, boost::optional<double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE((boost::is_base_of<boost::optional_detail::tc_optional_base<CustomizedTrivial>, boost::optional<CustomizedTrivial> > ));
|
||||
BOOST_TEST_TRAIT_FALSE((boost::is_base_of<boost::optional_detail::tc_optional_base<DeletedDefault>, boost::optional<DeletedDefault> > ));
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<int> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<CustomizedTrivial> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<Empty> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<Aggregate<int, double> > > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<Aggregate<Aggregate<Empty, int>, double> > > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<DeletedDefault> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<int> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<CustomizedTrivial> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<Empty> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<Aggregate<int, double> > > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<Aggregate<Aggregate<Empty, int>, double> > > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<boost::optional<DeletedDefault> > ));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -29,4 +29,3 @@ void test_implicit_conversion_to_bool()
|
||||
boost::optional<T> opt;
|
||||
opt.value_or(U());
|
||||
}
|
||||
|
||||
|
||||
@@ -240,8 +240,8 @@ void test_flat_map_move_only()
|
||||
{
|
||||
{
|
||||
optional<MoveOnly> om (makeMoveOnly(1)), om2 (makeMoveOnly(2));
|
||||
verify_type<optional<int> >(boost::move(om).flat_map(get_val));
|
||||
optional<int> oi = boost::move(om2).flat_map(get_val);
|
||||
verify_type<optional<int> >(std::move(om).flat_map(get_val));
|
||||
optional<int> oi = std::move(om2).flat_map(get_val);
|
||||
BOOST_TEST(bool(oi));
|
||||
BOOST_TEST_EQ(2, *oi);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2026 Andrzej Krzemienski.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/lib/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
|
||||
#include "boost/optional/optional_fwd.hpp"
|
||||
#include "boost/optional/optional.hpp"
|
||||
|
||||
void statically_test_basic_instantiations()
|
||||
{
|
||||
boost::optional<int> oN, o1(1);
|
||||
swap(oN, o1);
|
||||
|
||||
int i = 1;
|
||||
boost::optional<int> rN, ri(i);
|
||||
swap(rN, ri);
|
||||
}
|
||||
@@ -105,9 +105,42 @@ 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();
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ struct Guard
|
||||
std::string str;
|
||||
Guard() : num() {}
|
||||
Guard(double num_, std::string str_) : num(num_), str(str_) {}
|
||||
|
||||
|
||||
friend bool operator==(const Guard& lhs, const Guard& rhs) { return lhs.num == rhs.num && lhs.str == rhs.str; }
|
||||
friend bool operator!=(const Guard& lhs, const Guard& rhs) { return !(lhs == rhs); }
|
||||
|
||||
|
||||
private:
|
||||
Guard(const Guard&);
|
||||
Guard& operator=(const Guard&);
|
||||
@@ -50,4 +50,4 @@ int main()
|
||||
NOTHING_TO_TEST_SO_JUST_FAIL
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ int get_val(MoveOnly m)
|
||||
void test_map_move_only()
|
||||
{
|
||||
optional<MoveOnly> om (makeMoveOnly(7)), om2 (makeMoveOnly(8));
|
||||
verify_type<optional<int> >(boost::move(om).map(get_val));
|
||||
optional<int> oi = boost::move(om2).map(get_val);
|
||||
verify_type<optional<int> >(std::move(om).map(get_val));
|
||||
optional<int> oi = std::move(om2).map(get_val);
|
||||
BOOST_TEST(bool(oi));
|
||||
BOOST_TEST_EQ(8, *oi);
|
||||
|
||||
@@ -72,7 +72,7 @@ void test_map_move_only()
|
||||
BOOST_TEST_EQ(4, *oj);
|
||||
|
||||
optional<MoveOnly> o_;
|
||||
optional<int> oi_ = boost::move(o_).map(get_val);
|
||||
optional<int> oi_ = std::move(o_).map(get_val);
|
||||
BOOST_TEST(!oi_);
|
||||
}
|
||||
|
||||
|
||||
+49
-49
@@ -75,14 +75,14 @@ void test_move_ctor_from_U()
|
||||
optional<Oracle> o1 ((OracleVal()));
|
||||
BOOST_TEST(o1);
|
||||
BOOST_TEST(o1->s == sValueMoveConstructed || o1->s == sMoveConstructed);
|
||||
|
||||
|
||||
OracleVal v1;
|
||||
optional<Oracle> o2 (v1);
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed );
|
||||
BOOST_TEST(v1.s == sIntConstructed);
|
||||
|
||||
optional<Oracle> o3 (boost::move(v1));
|
||||
|
||||
optional<Oracle> o3 (std::move(v1));
|
||||
BOOST_TEST(o3);
|
||||
BOOST_TEST(o3->s == sValueMoveConstructed || o3->s == sMoveConstructed);
|
||||
BOOST_TEST(v1.s == sMovedFrom);
|
||||
@@ -93,14 +93,14 @@ void test_move_ctor_form_T()
|
||||
optional<Oracle> o1 ((Oracle()));
|
||||
BOOST_TEST(o1);
|
||||
BOOST_TEST(o1->s == sMoveConstructed);
|
||||
|
||||
|
||||
Oracle v1;
|
||||
optional<Oracle> o2 (v1);
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->s == sCopyConstructed);
|
||||
BOOST_TEST(v1.s == sDefaultConstructed);
|
||||
|
||||
optional<Oracle> o3 (boost::move(v1));
|
||||
|
||||
optional<Oracle> o3 (std::move(v1));
|
||||
BOOST_TEST(o3);
|
||||
BOOST_TEST(o3->s == sMoveConstructed);
|
||||
BOOST_TEST(v1.s == sMovedFrom);
|
||||
@@ -109,25 +109,25 @@ void test_move_ctor_form_T()
|
||||
void test_move_ctor_from_optional_T()
|
||||
{
|
||||
optional<Oracle> o1;
|
||||
optional<Oracle> o2(boost::move(o1));
|
||||
|
||||
optional<Oracle> o2(std::move(o1));
|
||||
|
||||
BOOST_TEST(!o1);
|
||||
BOOST_TEST(!o2);
|
||||
|
||||
|
||||
optional<Oracle> o3((Oracle()));
|
||||
optional<Oracle> o4(boost::move(o3));
|
||||
optional<Oracle> o4(std::move(o3));
|
||||
BOOST_TEST(o3);
|
||||
BOOST_TEST(o4);
|
||||
BOOST_TEST(o3->s == sMovedFrom);
|
||||
BOOST_TEST(o4->s == sMoveConstructed);
|
||||
|
||||
|
||||
optional<Oracle> o5((optional<Oracle>()));
|
||||
BOOST_TEST(!o5);
|
||||
|
||||
|
||||
optional<Oracle> o6((optional<Oracle>(Oracle())));
|
||||
BOOST_TEST(o6);
|
||||
BOOST_TEST(o6->s == sMoveConstructed);
|
||||
|
||||
|
||||
optional<Oracle> o7(o6); // does copy ctor from non-const lvalue compile?
|
||||
}
|
||||
|
||||
@@ -137,13 +137,13 @@ void test_move_assign_from_U()
|
||||
o1 = boost::none; // test if additional assignments didn't break it
|
||||
o1 = OracleVal();
|
||||
BOOST_TEST(o1);
|
||||
|
||||
BOOST_TEST(o1->s == sValueMoveConstructed);
|
||||
|
||||
|
||||
BOOST_TEST(o1->s == sValueMoveConstructed);
|
||||
|
||||
o1 = OracleVal();
|
||||
BOOST_TEST(o1);
|
||||
BOOST_TEST(o1->s == sMoveAssigned);
|
||||
|
||||
BOOST_TEST(o1->s == sMoveAssigned || o1->s == sValueMoveAssigned);
|
||||
|
||||
OracleVal v1;
|
||||
optional<Oracle> o2;
|
||||
o2 = v1;
|
||||
@@ -152,11 +152,11 @@ void test_move_assign_from_U()
|
||||
BOOST_TEST(v1.s == sIntConstructed);
|
||||
o2 = v1;
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->s == sCopyAssigned || o2->s == sMoveAssigned);
|
||||
BOOST_TEST(o2->s == sCopyAssigned || o2->s == sMoveAssigned || o2->s == sValueCopyAssigned);
|
||||
BOOST_TEST(v1.s == sIntConstructed);
|
||||
|
||||
|
||||
optional<Oracle> o3;
|
||||
o3 = boost::move(v1);
|
||||
o3 = std::move(v1);
|
||||
BOOST_TEST(o3);
|
||||
BOOST_TEST(o3->s == sValueMoveConstructed);
|
||||
BOOST_TEST(v1.s == sMovedFrom);
|
||||
@@ -167,12 +167,12 @@ void test_move_assign_from_T()
|
||||
optional<Oracle> o1;
|
||||
o1 = Oracle();
|
||||
BOOST_TEST(o1);
|
||||
BOOST_TEST(o1->s == sMoveConstructed);
|
||||
|
||||
BOOST_TEST(o1->s == sMoveConstructed);
|
||||
|
||||
o1 = Oracle();
|
||||
BOOST_TEST(o1);
|
||||
BOOST_TEST(o1->s == sMoveAssigned);
|
||||
|
||||
BOOST_TEST(o1->s == sMoveAssigned);
|
||||
|
||||
Oracle v1;
|
||||
optional<Oracle> o2;
|
||||
o2 = v1;
|
||||
@@ -183,9 +183,9 @@ void test_move_assign_from_T()
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->s == sCopyAssigned);
|
||||
BOOST_TEST(v1.s == sDefaultConstructed);
|
||||
|
||||
|
||||
optional<Oracle> o3;
|
||||
o3 = boost::move(v1);
|
||||
o3 = std::move(v1);
|
||||
BOOST_TEST(o3);
|
||||
BOOST_TEST(o3->s == sMoveConstructed);
|
||||
BOOST_TEST(v1.s == sMovedFrom);
|
||||
@@ -203,13 +203,13 @@ void test_move_assign_from_optional_T()
|
||||
BOOST_TEST(o3->s == sMoveConstructed);
|
||||
BOOST_TEST(o1);
|
||||
BOOST_TEST(o1->s == sCopyConstructed);
|
||||
|
||||
o2 = boost::move(o3);
|
||||
|
||||
o2 = std::move(o3);
|
||||
BOOST_TEST(o3);
|
||||
BOOST_TEST(o3->s == sMovedFrom);
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->s == sMoveConstructed);
|
||||
|
||||
|
||||
o2 = optional<Oracle>((Oracle()));
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->s == sMoveAssigned);
|
||||
@@ -222,11 +222,11 @@ public:
|
||||
MoveOnly(int v) : val(v) {}
|
||||
MoveOnly(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; }
|
||||
void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; }
|
||||
|
||||
|
||||
private:
|
||||
MoveOnly(MoveOnly const&);
|
||||
void operator=(MoveOnly const&);
|
||||
|
||||
|
||||
friend class MoveOnlyB;
|
||||
};
|
||||
|
||||
@@ -236,15 +236,15 @@ void test_with_move_only()
|
||||
optional<MoveOnly> o2((MoveOnly(1)));
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->val == 1);
|
||||
optional<MoveOnly> o3 (boost::move(o1));
|
||||
optional<MoveOnly> o3 (std::move(o1));
|
||||
BOOST_TEST(!o3);
|
||||
optional<MoveOnly> o4 (boost::move(o2));
|
||||
optional<MoveOnly> o4 (std::move(o2));
|
||||
BOOST_TEST(o4);
|
||||
BOOST_TEST(o4->val == 1);
|
||||
BOOST_TEST(o2);
|
||||
BOOST_TEST(o2->val == 0);
|
||||
|
||||
o3 = boost::move(o4);
|
||||
|
||||
o3 = std::move(o4);
|
||||
BOOST_TEST(o3);
|
||||
BOOST_TEST(o3->val == 1);
|
||||
BOOST_TEST(o4);
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
void operator=(MoveOnlyB&& rhs) {val = rhs.val; rhs.val = 0; }
|
||||
MoveOnlyB(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; }
|
||||
void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; }
|
||||
|
||||
|
||||
private:
|
||||
MoveOnlyB(MoveOnlyB const&);
|
||||
void operator=(MoveOnlyB const&);
|
||||
@@ -272,15 +272,15 @@ void test_move_assign_from_optional_U()
|
||||
{
|
||||
optional<MoveOnly> a((MoveOnly(2)));
|
||||
optional<MoveOnlyB> b1;
|
||||
b1 = boost::move(a);
|
||||
|
||||
b1 = std::move(a);
|
||||
|
||||
BOOST_TEST(b1);
|
||||
BOOST_TEST(b1->val == 2);
|
||||
BOOST_TEST(a);
|
||||
BOOST_TEST(a->val == 0);
|
||||
|
||||
|
||||
b1 = MoveOnly(4);
|
||||
|
||||
|
||||
BOOST_TEST(b1);
|
||||
BOOST_TEST(b1->val == 4);
|
||||
}
|
||||
@@ -288,15 +288,15 @@ void test_move_assign_from_optional_U()
|
||||
void test_move_ctor_from_optional_U()
|
||||
{
|
||||
optional<MoveOnly> a((MoveOnly(2)));
|
||||
optional<MoveOnlyB> b1(boost::move(a));
|
||||
|
||||
optional<MoveOnlyB> b1(std::move(a));
|
||||
|
||||
BOOST_TEST(b1);
|
||||
BOOST_TEST(b1->val == 2);
|
||||
BOOST_TEST(a);
|
||||
BOOST_TEST(a->val == 0);
|
||||
|
||||
|
||||
optional<MoveOnlyB> b2(( optional<MoveOnly>(( MoveOnly(4) )) ));
|
||||
|
||||
|
||||
BOOST_TEST(b2);
|
||||
BOOST_TEST(b2->val == 4);
|
||||
}
|
||||
@@ -306,7 +306,7 @@ void test_swap()
|
||||
optional<MoveOnly> a((MoveOnly(2)));
|
||||
optional<MoveOnly> b((MoveOnly(3)));
|
||||
swap(a, b);
|
||||
|
||||
|
||||
BOOST_TEST(a->val == 3);
|
||||
BOOST_TEST(b->val == 2);
|
||||
}
|
||||
@@ -317,13 +317,13 @@ void test_optional_ref_to_movables()
|
||||
optional<MoveOnly&> orm = m;
|
||||
orm->val = 2;
|
||||
BOOST_TEST(m.val == 2);
|
||||
|
||||
|
||||
optional<MoveOnly&> orm2 = orm;
|
||||
orm2->val = 1;
|
||||
BOOST_TEST(m.val == 1);
|
||||
BOOST_TEST(orm->val == 1);
|
||||
|
||||
optional<MoveOnly&> orm3 = boost::move(orm);
|
||||
|
||||
optional<MoveOnly&> orm3 = std::move(orm);
|
||||
orm3->val = 4;
|
||||
BOOST_TEST(m.val == 4);
|
||||
BOOST_TEST(orm->val == 4);
|
||||
|
||||
@@ -29,13 +29,16 @@ void test()
|
||||
{
|
||||
#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
boost::optional<int> v = Wrapper();
|
||||
BOOST_TEST(v);
|
||||
//BOOST_TEST(v);
|
||||
boost::optional<boost::optional<int>> vv;
|
||||
bool xx = vv?true : false;
|
||||
(void)xx;
|
||||
BOOST_TEST_EQ(*v, 7);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test();
|
||||
return boost::report_errors();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
|
||||
#include "boost/static_assert.hpp"
|
||||
#include "boost/optional/optional.hpp"
|
||||
|
||||
#ifdef BOOST_BORLANDC
|
||||
@@ -44,36 +43,36 @@ struct NothrowNone {
|
||||
#if 0 // these also test type_traits, which are wrong
|
||||
void test_noexcept_as_defined() // this is a compile-time test
|
||||
{
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible<NothrowBoth>::value);
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable<NothrowBoth>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible<NothrowCtor>::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<NothrowCtor>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible<NothrowAssign>::value);
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable<NothrowAssign>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible<NothrowNone>::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<NothrowNone>::value);
|
||||
static_assert(::boost::is_nothrow_move_constructible<NothrowBoth>::value, "ERROR");
|
||||
static_assert(::boost::is_nothrow_move_assignable<NothrowBoth>::value, "ERROR");
|
||||
|
||||
static_assert(::boost::is_nothrow_move_constructible<NothrowCtor>::value, "ERROR");
|
||||
static_assert(!::boost::is_nothrow_move_assignable<NothrowCtor>::value, "ERROR");
|
||||
|
||||
static_assert(!::boost::is_nothrow_move_constructible<NothrowAssign>::value, "ERROR");
|
||||
static_assert(::boost::is_nothrow_move_assignable<NothrowAssign>::value, "ERROR");
|
||||
|
||||
static_assert(!::boost::is_nothrow_move_constructible<NothrowNone>::value, "ERROR");
|
||||
static_assert(!::boost::is_nothrow_move_assignable<NothrowNone>::value, "ERROR");
|
||||
}
|
||||
|
||||
void test_noexcept_on_optional_with_type_traits() // this is a compile-time test
|
||||
{
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible<optional<NothrowBoth> >::value);
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable<optional<NothrowBoth> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowBoth>()));
|
||||
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible<optional<NothrowCtor> >::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<optional<NothrowCtor> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowCtor>()));
|
||||
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible<optional<NothrowAssign> >::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<optional<NothrowAssign> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowAssign>()));
|
||||
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible<optional<NothrowNone> >::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<optional<NothrowNone> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowNone>()));
|
||||
static_assert(::boost::is_nothrow_move_constructible<optional<NothrowBoth> >::value, "ERROR");
|
||||
static_assert(::boost::is_nothrow_move_assignable<optional<NothrowBoth> >::value, "ERROR");
|
||||
static_assert(BOOST_NOEXCEPT_EXPR(optional<NothrowBoth>()), "ERROR");
|
||||
|
||||
static_assert(::boost::is_nothrow_move_constructible<optional<NothrowCtor> >::value, "ERROR");
|
||||
static_assert(!::boost::is_nothrow_move_assignable<optional<NothrowCtor> >::value, "ERROR");
|
||||
static_assert(BOOST_NOEXCEPT_EXPR(optional<NothrowCtor>()), "ERROR");
|
||||
|
||||
static_assert(!::boost::is_nothrow_move_constructible<optional<NothrowAssign> >::value, "ERROR");
|
||||
static_assert(!::boost::is_nothrow_move_assignable<optional<NothrowAssign> >::value, "ERROR");
|
||||
static_assert(BOOST_NOEXCEPT_EXPR(optional<NothrowAssign>()), "ERROR");
|
||||
|
||||
static_assert(!::boost::is_nothrow_move_constructible<optional<NothrowNone> >::value, "ERROR");
|
||||
static_assert(!::boost::is_nothrow_move_assignable<optional<NothrowNone> >::value, "ERROR");
|
||||
static_assert(BOOST_NOEXCEPT_EXPR(optional<NothrowNone>()), "ERROR");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -87,22 +86,22 @@ void test_noexcept_optional_with_operator() // compile-time test
|
||||
ONxC onxC;
|
||||
ONxA onxA;
|
||||
ONx0 onx0;
|
||||
|
||||
BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONx2() ));
|
||||
BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONx2(boost::move(onx2)) ));
|
||||
BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( onx2 = ONx2() ));
|
||||
|
||||
BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONxC() ));
|
||||
BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONxC(boost::move(onxC)) ));
|
||||
BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( onxC = ONxC() ));
|
||||
|
||||
BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONxA() ));
|
||||
BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( ONxA(boost::move(onxA)) ));
|
||||
BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( onxA = ONxA() ));
|
||||
|
||||
BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONx0() ));
|
||||
BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( ONx0(boost::move(onx0)) ));
|
||||
BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( onx0 = ONx0() ));
|
||||
|
||||
static_assert( BOOST_NOEXCEPT_EXPR( ONx2() ), "ERROR");
|
||||
static_assert( BOOST_NOEXCEPT_EXPR( ONx2(std::move(onx2)) ), "ERROR");
|
||||
static_assert( BOOST_NOEXCEPT_EXPR( onx2 = ONx2() ), "ERROR");
|
||||
|
||||
static_assert( BOOST_NOEXCEPT_EXPR( ONxC() ), "ERROR");
|
||||
static_assert( BOOST_NOEXCEPT_EXPR( ONxC(std::move(onxC)) ), "ERROR");
|
||||
static_assert(!BOOST_NOEXCEPT_EXPR( onxC = ONxC() ), "ERROR");
|
||||
|
||||
static_assert( BOOST_NOEXCEPT_EXPR( ONxA() ), "ERROR");
|
||||
static_assert(!BOOST_NOEXCEPT_EXPR( ONxA(std::move(onxA)) ), "ERROR");
|
||||
static_assert(!BOOST_NOEXCEPT_EXPR( onxA = ONxA() ), "ERROR");
|
||||
|
||||
static_assert( BOOST_NOEXCEPT_EXPR( ONx0() ), "ERROR");
|
||||
static_assert(!BOOST_NOEXCEPT_EXPR( ONx0(std::move(onx0)) ), "ERROR");
|
||||
static_assert(!BOOST_NOEXCEPT_EXPR( onx0 = ONx0() ), "ERROR");
|
||||
}
|
||||
|
||||
#endif // !defined BOOST_NO_CXX11_NOEXCEPT
|
||||
@@ -112,5 +111,3 @@ int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
#include "boost/optional/optional.hpp"
|
||||
|
||||
#include "boost/core/enable_if.hpp"
|
||||
#include "boost/type_traits/is_constructible.hpp"
|
||||
|
||||
#ifdef BOOST_BORLANDC
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
@@ -66,7 +69,7 @@ int main()
|
||||
optFs1 = optFs2;
|
||||
|
||||
// the following still fails although it shouldn't
|
||||
//BOOST_STATIC_ASSERT((std::is_copy_constructible<boost::optional<Path>>::value));
|
||||
//static_assert((std::is_copy_constructible<boost::optional<Path>>::value), "ERROR");
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -26,7 +26,7 @@ int main()
|
||||
#ifdef BOOST_OPTIONAL_CONFIG_NO_PROPER_ASSIGN_FROM_CONST_INT
|
||||
test_converting_assignment<const int, const int>();
|
||||
#else
|
||||
BOOST_STATIC_ASSERT_MSG(false, "EXPECTED TEST COMPILE-TIME FAILURE");
|
||||
static_assert(false, "EXPECTED TEST COMPILE-TIME FAILURE");
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/lib/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// fernando_cacciola@hotmail.com
|
||||
//
|
||||
#include "boost/optional.hpp"
|
||||
|
||||
//
|
||||
// THIS TEST SHOULD FAIL TO COMPILE
|
||||
//
|
||||
void optional_reference__test_no_converting_initialization()
|
||||
{
|
||||
boost::optional<const int&> o (boost::optional<int>(1));
|
||||
(void)o;
|
||||
}
|
||||
@@ -24,7 +24,13 @@ using boost::none;
|
||||
struct Value
|
||||
{
|
||||
int val;
|
||||
explicit Value(int v) : val(v) {}
|
||||
BOOST_CONSTEXPR explicit Value(int v) : val(v) {}
|
||||
};
|
||||
|
||||
struct Guard
|
||||
{
|
||||
int val;
|
||||
BOOST_CONSTEXPR explicit Guard(int v) : val(v) {}
|
||||
};
|
||||
|
||||
int val(int const& i)
|
||||
@@ -37,6 +43,11 @@ 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)
|
||||
{
|
||||
@@ -47,21 +58,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));
|
||||
}
|
||||
@@ -70,29 +81,121 @@ 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()
|
||||
{
|
||||
@@ -100,17 +203,21 @@ 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();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2014 Andrzej Krzemienski.
|
||||
// Copyright (C) 2014, 2026 Andrzej Krzemienski.
|
||||
//
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -9,6 +9,7 @@
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
|
||||
#include <boost/type_traits/is_constructible.hpp>
|
||||
#include "boost/optional/optional.hpp"
|
||||
|
||||
#ifdef BOOST_BORLANDC
|
||||
@@ -21,29 +22,29 @@ using boost::optional;
|
||||
|
||||
struct X {};
|
||||
struct Y {};
|
||||
|
||||
|
||||
struct Resource
|
||||
{
|
||||
explicit Resource(const X&) {}
|
||||
};
|
||||
|
||||
BOOST_STATIC_ASSERT(( boost::is_constructible<Resource, const X&>::value ));
|
||||
BOOST_STATIC_ASSERT(( !boost::is_constructible<Resource, const Y&>::value ));
|
||||
static_assert(( boost::is_constructible<Resource, const X&>::value ), "ERROR");
|
||||
static_assert(( !boost::is_constructible<Resource, const Y&>::value ), "ERROR");
|
||||
|
||||
BOOST_STATIC_ASSERT(( boost::is_constructible<optional<Resource>, const X&>::value ));
|
||||
BOOST_STATIC_ASSERT(( !boost::is_constructible<optional<Resource>, const Y&>::value ));
|
||||
static_assert(( boost::is_constructible<optional<Resource>, const X&>::value ), "ERROR");
|
||||
static_assert(( !boost::is_constructible<optional<Resource>, const Y&>::value ), "ERROR");
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS
|
||||
BOOST_STATIC_ASSERT(( boost::is_constructible< optional< optional<int> >, optional<int> >::value ));
|
||||
BOOST_STATIC_ASSERT(( !boost::is_constructible< optional<int>, optional< optional<int> > >::value ));
|
||||
static_assert(( boost::is_constructible< optional< optional<int> >, optional<int> >::value ), "ERROR");
|
||||
static_assert(( !boost::is_constructible< optional<int>, optional< optional<int> > >::value ), "ERROR");
|
||||
|
||||
BOOST_STATIC_ASSERT(( boost::is_constructible< optional< optional<int> >, const optional<int>& >::value ));
|
||||
BOOST_STATIC_ASSERT(( !boost::is_constructible< optional<int>, const optional< optional<int> >& >::value ));
|
||||
static_assert(( boost::is_constructible< optional< optional<int> >, const optional<int>& >::value ), "ERROR");
|
||||
static_assert(( !boost::is_constructible< optional<int>, const optional< optional<int> >& >::value ), "ERROR");
|
||||
|
||||
BOOST_STATIC_ASSERT(( boost::is_constructible<optional<Resource>, const optional<X>&>::value ));
|
||||
BOOST_STATIC_ASSERT(( !boost::is_constructible<optional<Resource>, const optional<Y>&>::value ));
|
||||
static_assert(( boost::is_constructible<optional<Resource>, const optional<X>&>::value ), "ERROR");
|
||||
static_assert(( !boost::is_constructible<optional<Resource>, const optional<Y>&>::value ), "ERROR");
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
int main() { }
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "boost/type_traits/is_base_of.hpp"
|
||||
#include "boost/optional/detail/experimental_traits.hpp"
|
||||
|
||||
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
|
||||
|
||||
struct PrivDefault
|
||||
@@ -43,9 +44,9 @@ struct DeletedDefault
|
||||
};
|
||||
|
||||
namespace boost { namespace optional_config {
|
||||
|
||||
|
||||
template <> struct optional_uses_direct_storage_for<CustomizedTrivial> : boost::true_type {};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
struct CustDtor
|
||||
@@ -78,40 +79,40 @@ void test_type_traits()
|
||||
// this only tests if type traits are implemented correctly
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<int> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<double> ));
|
||||
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_config::optional_uses_direct_storage_for<CustomizedTrivial> ));
|
||||
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<PrivDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<NoDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, CustDefault> > ));
|
||||
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustDtor> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustAssign> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<CustMove> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, CustMove> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<int> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<double> ));
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<int> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<double> ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Empty> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, double> > ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<Aggregate<Empty, int>, double> > ));
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Empty> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<int, double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<Aggregate<Empty, int>, double> > ));
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Empty> ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Aggregate<int, double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<Aggregate<Aggregate<Empty, int>, double> > ));
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<DeletedDefault> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_config::optional_uses_direct_storage_for<Aggregate<int, DeletedDefault> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<CustDtor> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<CustAssign> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<CustMove> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<Aggregate<int, CustMove> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<CustDtor> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<CustAssign> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<CustMove> ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<Aggregate<int, CustMove> > ));
|
||||
}
|
||||
|
||||
void test_trivial_copyability()
|
||||
@@ -120,27 +121,30 @@ void test_trivial_copyability()
|
||||
BOOST_TEST_TRAIT_TRUE((boost::is_base_of<boost::optional_detail::tc_optional_base<double>, boost::optional<double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE((boost::is_base_of<boost::optional_detail::tc_optional_base<CustomizedTrivial>, boost::optional<CustomizedTrivial> > ));
|
||||
BOOST_TEST_TRAIT_FALSE((boost::is_base_of<boost::optional_detail::tc_optional_base<DeletedDefault>, boost::optional<DeletedDefault> > ));
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_SPEC_FOR_TRIVIAL_TYPES
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<int> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<CustomizedTrivial> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<DeletedDefault> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<int> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<double> > ));
|
||||
BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_trivially_semiregular<boost::optional<CustomizedTrivial> > ));
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<boost::optional<DeletedDefault> > ));
|
||||
#endif
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<Empty> > ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<Aggregate<int, double> > > ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable<boost::optional<Aggregate<Aggregate<Empty, int>, double> > > ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<boost::optional<Empty> > ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<boost::optional<Aggregate<int, double> > > ));
|
||||
BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_trivially_semiregular<boost::optional<Aggregate<Aggregate<Empty, int>, double> > > ));
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
#ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
|
||||
test_type_traits();
|
||||
test_trivial_copyability();
|
||||
#endif
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
//
|
||||
|
||||
#include "boost/optional/optional.hpp"
|
||||
#include "boost/utility/in_place_factory.hpp"
|
||||
|
||||
#ifdef BOOST_BORLANDC
|
||||
#pragma hdrstop
|
||||
@@ -189,9 +188,9 @@ namespace optional_swap_test
|
||||
return;
|
||||
|
||||
if( !hasX )
|
||||
x = boost::in_place('\0');
|
||||
x.emplace('\0');
|
||||
else if ( !hasY )
|
||||
y = boost::in_place('\0');
|
||||
y.emplace('\0');
|
||||
|
||||
optional_swap_test::swap(*x,*y);
|
||||
|
||||
@@ -211,6 +210,7 @@ namespace boost {
|
||||
// Compile time tweaking on whether or not swap should use the default constructor:
|
||||
//
|
||||
|
||||
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
template <> struct optional_swap_should_use_default_constructor<
|
||||
optional_swap_test::class_whose_default_ctor_should_be_used> : true_type {} ;
|
||||
|
||||
@@ -219,7 +219,7 @@ template <> struct optional_swap_should_use_default_constructor<
|
||||
|
||||
template <class T> struct optional_swap_should_use_default_constructor<
|
||||
optional_swap_test::template_whose_default_ctor_should_be_used<T> > : true_type {} ;
|
||||
|
||||
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
|
||||
//
|
||||
// Specialization of boost::swap:
|
||||
@@ -353,15 +353,19 @@ void test_swap_member_function( T const* )
|
||||
void test_swap_tweaking()
|
||||
{
|
||||
( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) );
|
||||
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
|
||||
( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) );
|
||||
( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) );
|
||||
( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
|
||||
( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) );
|
||||
#endif
|
||||
( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) );
|
||||
#ifndef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
|
||||
( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
|
||||
( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) );
|
||||
( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) );
|
||||
( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
|
||||
( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include "boost/optional/detail/optional_config.hpp"
|
||||
#include "boost/predef.h"
|
||||
//#include "boost/predef.h"
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
@@ -19,13 +19,13 @@ int main()
|
||||
#if defined(__GNUC__)
|
||||
|
||||
std::string emptys;
|
||||
|
||||
|
||||
#ifdef BOOST_INTEL_CXX_VERSION
|
||||
BOOST_TEST_EQ(emptys, "HAS INTEL INSIDE");
|
||||
#else
|
||||
BOOST_TEST_EQ(emptys, "NO INTEL INSIDE");
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
BOOST_TEST_EQ(emptys, "HAS RVALUE REFS");
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user