Skip to content

Commit aaabe89

Browse files
committed
Merge branch 'develop'
2 parents d46b9c3 + fa52755 commit aaabe89

10 files changed

Lines changed: 217 additions & 19 deletions

doc/11_development.qbk

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ In the general case, the internal representation is something equivalent to:
5050
alignas(T) char _value [sizeof(T)];
5151
};
5252

53+
or:
54+
55+
template <typename T>
56+
class Optional
57+
{
58+
bool _has_value = false;
59+
union {
60+
T _value;
61+
DummyType _non_value;
62+
};
63+
};
64+
5365
Next, because we need to pass around these "optional" `int`s as normal `int`s,
5466
like returning them from functions, when copying, we need to copy `_has_value`,
5567
which indicates whether we have the value or not, and, if we do have value, and

doc/27_ref_optional_synopsis.qbk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ They are empty, trivially copyable classes with disabled default constructor.
197197
template<class F> constexpr auto flat_map( F f ) & -> ``['see below]``; ``[link reference_optional_flat_map __GO_TO__]``
198198
template<class F> constexpr auto flat_map( F f ) && -> ``['see below]``; ``[link reference_optional_flat_map_move __GO_TO__]``
199199

200+
constexpr operator optional<T&>() & noexcept; ``[link reference_optional_conversion_to_ref __GO_TO__]``
201+
constexpr operator optional<T const&>() const& noexcept; ``[link reference_optional_conversion_to_ref __GO_TO__]``
202+
200203
T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]``
201204
T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]``
202205

doc/28_ref_optional_semantics.qbk

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ the parameter.
4747
* [*Example:]
4848
``
4949
#include <boost/none.hpp>
50+
5051
optional<T> n(none) ;
5152
assert ( !n ) ;
53+
assert ( n == none ) ;
5254
``
5355

5456
__SPACE__
@@ -751,6 +753,26 @@ __SPACE__
751753

752754
__SPACE__
753755

756+
757+
[#reference_optional_conversion_to_ref]
758+
759+
[: `constexpr optional<T>::operator optional<T&>() & noexcept ;`]
760+
761+
* [*Returns:] If `*this` contains a value `optional<T&>(**this)`, otherwise `optional<T&>()`.
762+
763+
[: `constexpr optional<T>::operator optional<T const&>() const& noexcept ;`]
764+
765+
* [*Returns:] If `*this` contains a value `optional<T const&>(**this)`, otherwise `optional<T&>()`.
766+
767+
* [*Example:]
768+
``
769+
const optional<int> oi = 1;
770+
optional<const int&> ri = oi;
771+
``
772+
773+
__SPACE__
774+
775+
754776
[#reference_optional_get_value_or_value]
755777

756778
[: `T const& optional<T>::get_value_or( T const& default) const ;`]

doc/90_dependencies.qbk

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ The implementation uses the following other Boost modules:
7272
# assert
7373
# config
7474
# core
75-
# static_assert
7675
# throw_exception
7776
# type_traits
7877

doc/91_comparison_with_std.qbk

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,8 @@
5656
void test(vector<optional<T>> rng, T val) {
5757
std::ranges::find(rng, make_optional(val));
5858
}
59-
```] [The same code for `std::optional` compiles but is ['undefined behavior] when `T` is itself an `optional`. ] ]
59+
```] [For `std::optional`, code without `make_optional()` compiles but is ['undefined behavior] when `T` is itself an `optional`. ] ]
6060

6161
]
6262

63-
6463
[endsect][/ std_comp]

doc/92_relnotes.qbk

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* In C++17 all constructors (including copy and move) become core constant expressions
2727
for co-operating types.
2828

29-
This addresses [@https://github.com/boostorg/optional/issues/143 issue #143].
29+
This addresses issues [@https://github.com/boostorg/optional/issues/132 #132] and [@https://github.com/boostorg/optional/issues/143 #143].
3030

3131
* *Breaking change.* In the said implementation, abandoned the mechanism for customizing
3232
`swap`. Hardly anyone knows about this mechanism and it was never documented.
@@ -37,10 +37,31 @@
3737
* Construct `o = u`, where `o` is of type `optional<T>` and `u` is of type `U` convertible to `T`,
3838
does not create a temporary `T`.
3939

40+
* In the said implementation, added a conversion from `optional<T>&` to `optional<T&>`. This addresses [@https://github.com/boostorg/optional/issues/142 issue #142].
41+
4042
* `none_t` is now `std::equality_comparable`, which means that `none_t` and `optional<T>`
4143
model concept `std::equality_comparable_with` (for `std::equality_comparable` `T`s),
4244
which means that you can `std::ranges::find(rng, boost::none)` for a range of optional objects.
4345

46+
* *Warning.* In the future releases we intend to introduce the range interface
47+
in `optional`, so that `std::ranges::range<optional<T>>` will be `true`.
48+
This may affect the overload resolution in programs that make decisions based
49+
on predicates such as `std::ranges::range`. For instance, the following code
50+
will start behaving differently:
51+
52+
```
53+
template <typename T>
54+
void serialize(T const& v)
55+
{
56+
if constexpr (std::ranges::range<T>)
57+
serialize_as_range(v);
58+
else if constexpr (custom::is_optional_like<T>)
59+
serialize_as_optional(v);
60+
else
61+
serialize_as_value(v);
62+
}
63+
```
64+
4465
[heading Boost Release 1.87]
4566

4667
* *Breaking change.* Dropped support for C++03. C++11 is now the required minimum; at least some C++11 features.

include/boost/optional/detail/union_optional.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,20 @@ namespace boost {
379379
: storage(in_place_init, optional_detail::forward_<Args>(args)...)
380380
{}
381381

382+
BOOST_CXX14_CONSTEXPR operator optional<T&>() & noexcept
383+
{
384+
return this->has_value() ? optional<T&>(**this) : optional<T&>();
385+
}
386+
387+
BOOST_CONSTEXPR operator optional<const T&>() const& noexcept
388+
{
389+
return this->has_value() ? optional<const T&>(**this) : optional<const T&>();
390+
}
391+
392+
BOOST_CXX14_CONSTEXPR operator optional<T&>() && noexcept = delete;
393+
BOOST_CONSTEXPR operator optional<const T&>() const&& noexcept = delete;
394+
395+
382396
BOOST_CXX14_CONSTEXPR void reset() noexcept
383397
{
384398
storage.reset();

test/Jamfile.v2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ project
2828
cxx11_explicit_conversion_operators
2929
# cxx11_noexcept
3030
cxx11_rvalue_references
31-
cxx11_static_assert
3231
cxx11_variadic_templates
3332
]
3433
;
@@ -81,6 +80,7 @@ compile-fail optional_test_fail3b.cpp ;
8180
compile-fail optional_test_ref_fail1.cpp ;
8281
compile-fail optional_test_ref_fail3.cpp ;
8382
compile-fail optional_test_ref_fail4.cpp ;
83+
compile-fail optional_test_ref_fail_convert_from_temporary_optional_T.cpp ;
8484
compile-fail optional_test_inplace_fail.cpp ;
8585
compile-fail optional_test_inplace_fail2.cpp ;
8686
compile-fail optional_test_fail_implicit_bool_convert.cpp ;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (C) 2003, Fernando Luis Cacciola Carballal.
2+
//
3+
// Use, modification, and distribution is subject to the Boost Software
4+
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
// See http://www.boost.org/lib/optional for documentation.
8+
//
9+
// You are welcome to contact the author at:
10+
// fernando_cacciola@hotmail.com
11+
//
12+
#include "boost/optional.hpp"
13+
14+
//
15+
// THIS TEST SHOULD FAIL TO COMPILE
16+
//
17+
void optional_reference__test_no_converting_initialization()
18+
{
19+
boost::optional<const int&> o (boost::optional<int>(1));
20+
(void)o;
21+
}

test/optional_test_ref_to_val.cpp

Lines changed: 121 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ using boost::none;
2424
struct Value
2525
{
2626
int val;
27-
explicit Value(int v) : val(v) {}
27+
BOOST_CONSTEXPR explicit Value(int v) : val(v) {}
28+
};
29+
30+
struct Guard
31+
{
32+
int val;
33+
BOOST_CONSTEXPR explicit Guard(int v) : val(v) {}
2834
};
2935

3036
int val(int const& i)
@@ -37,6 +43,11 @@ int val(Value const& v)
3743
return v.val;
3844
}
3945

46+
int val(Guard const& v)
47+
{
48+
return v.val;
49+
}
50+
4051
template <typename Tref>
4152
optional<Tref&> make_opt_ref(Tref& v)
4253
{
@@ -47,21 +58,21 @@ template <typename Tval, typename Tref>
4758
void test_construct_from_optional_ref()
4859
{
4960
Tref v1 (1), v2 (2);
50-
61+
5162
optional<Tref&> opt_ref0;
5263
optional<Tref&> opt_ref1 (v1);
53-
64+
5465
optional<Tval> opt_val0 (opt_ref0);
5566
optional<Tval> opt_val1 (opt_ref1);
5667
optional<Tval> opt_val2 (make_opt_ref(v2));
57-
68+
5869
BOOST_TEST (!opt_val0);
5970
BOOST_TEST (opt_val1);
6071
BOOST_TEST (opt_val2);
61-
72+
6273
BOOST_TEST_EQ (1, val(*opt_val1));
6374
BOOST_TEST_EQ (2, val(*opt_val2));
64-
75+
6576
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
6677
BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2));
6778
}
@@ -70,47 +81,143 @@ template <typename Tval, typename Tref>
7081
void test_assign_from_optional_ref()
7182
{
7283
Tref v1 (1), v2 (2);
73-
84+
7485
optional<Tref&> opt_ref0;
7586
optional<Tref&> opt_ref1 (v1);
76-
87+
7788
optional<Tval> opt_val0;
7889
optional<Tval> opt_val1;
7990
optional<Tval> opt_val2;
80-
91+
8192
opt_val0 = opt_ref0;
8293
opt_val1 = opt_ref1;
8394
opt_val2 = make_opt_ref(v2);
84-
95+
8596
BOOST_TEST (!opt_val0);
8697
BOOST_TEST (opt_val1);
8798
BOOST_TEST (opt_val2);
88-
99+
89100
BOOST_TEST_EQ (1, val(*opt_val1));
90101
BOOST_TEST_EQ (2, val(*opt_val2));
91-
102+
92103
BOOST_TEST (boost::addressof(*opt_val1) != boost::addressof(v1));
93104
BOOST_TEST (boost::addressof(*opt_val2) != boost::addressof(v2));
94105
}
95106

107+
template <typename T>
108+
void test_convert_optional_T_to_optional_T_ref()
109+
{
110+
#ifdef BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
111+
using boost::optional;
112+
using boost::in_place_init;
113+
114+
{ // optional<T>& -> optional<T&>
115+
optional<T> ovN, ov1(in_place_init, 1), ov2(in_place_init, 2);
116+
117+
optional<T&> orN = ovN;
118+
optional<T&> or1 = ov1;
119+
optional<T&> or2 = ov2;
120+
121+
BOOST_TEST_EQ (!!orN, !!ovN);
122+
BOOST_TEST_EQ (!!or1, !!ov1);
123+
BOOST_TEST_EQ (!!or2, !!ov2);
124+
125+
BOOST_TEST (or1);
126+
BOOST_TEST (or2);
127+
BOOST_TEST_EQ (val(*or1), 1);
128+
BOOST_TEST_EQ (val(*or2), 2);
129+
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
130+
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
131+
}
132+
133+
{ // const optional<T>& -> optional<const T&>
134+
constexpr optional<T> ovN;
135+
constexpr optional<T> ov1(in_place_init, 1);
136+
constexpr optional<T> ov2(in_place_init, 2);
137+
138+
optional<const T&> orN = ovN;
139+
optional<const T&> or1 = ov1;
140+
optional<const T&> or2 = ov2;
141+
142+
BOOST_TEST_EQ (!!orN, !!ovN);
143+
BOOST_TEST_EQ (!!or1, !!ov1);
144+
BOOST_TEST_EQ (!!or2, !!ov2);
145+
146+
BOOST_TEST (or1);
147+
BOOST_TEST (or2);
148+
BOOST_TEST_EQ (val(*or1), 1);
149+
BOOST_TEST_EQ (val(*or2), 2);
150+
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
151+
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
152+
}
153+
154+
{ // optional<const T>& -> optional<const T&>
155+
optional<const T> ovN;
156+
optional<const T> ov1(in_place_init, 1);
157+
optional<const T> ov2(in_place_init, 2);
158+
159+
optional<const T&> orN = ovN;
160+
optional<const T&> or1 = ov1;
161+
optional<const T&> or2 = ov2;
162+
163+
BOOST_TEST_EQ (!!orN, !!ovN);
164+
BOOST_TEST_EQ (!!or1, !!ov1);
165+
BOOST_TEST_EQ (!!or2, !!ov2);
166+
167+
BOOST_TEST (or1);
168+
BOOST_TEST (or2);
169+
BOOST_TEST_EQ (val(*or1), 1);
170+
BOOST_TEST_EQ (val(*or2), 2);
171+
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
172+
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
173+
}
174+
175+
{ // optional<T>& -> optional<const T&>
176+
optional<T> ovN;
177+
optional<T> ov1(in_place_init, 1);
178+
optional<T> ov2(in_place_init, 2);
179+
180+
optional<const T&> orN = ovN;
181+
optional<const T&> or1 = ov1;
182+
optional<const T&> or2 = ov2;
183+
184+
BOOST_TEST_EQ (!!orN, !!ovN);
185+
BOOST_TEST_EQ (!!or1, !!ov1);
186+
BOOST_TEST_EQ (!!or2, !!ov2);
187+
188+
BOOST_TEST (or1);
189+
BOOST_TEST (or2);
190+
BOOST_TEST_EQ (val(*or1), 1);
191+
BOOST_TEST_EQ (val(*or2), 2);
192+
BOOST_TEST (boost::addressof(*or1) == boost::addressof(*ov1));
193+
BOOST_TEST (boost::addressof(*or2) == boost::addressof(*ov2));
194+
}
195+
196+
#endif // BOOST_OPTIONAL_USES_UNION_IMPLEMENTATION
197+
}
198+
96199

97200
int main()
98201
{
99202
test_construct_from_optional_ref<int, int>();
100203
test_construct_from_optional_ref<int, int const>();
101204
test_construct_from_optional_ref<int const, int const>();
102205
test_construct_from_optional_ref<int const, int>();
103-
206+
104207
test_construct_from_optional_ref<Value, Value>();
105208
test_construct_from_optional_ref<Value, Value const>();
106209
test_construct_from_optional_ref<Value const, Value const>();
107210
test_construct_from_optional_ref<Value const, Value>();
108-
211+
109212
test_assign_from_optional_ref<int, int>();
110213
test_assign_from_optional_ref<int, int const>();
111214

112215
test_assign_from_optional_ref<Value, Value>();
113216
test_assign_from_optional_ref<Value, Value const>();
114217

218+
test_convert_optional_T_to_optional_T_ref<int>();
219+
test_convert_optional_T_to_optional_T_ref<Value>();
220+
test_convert_optional_T_to_optional_T_ref<Guard>();
221+
115222
return boost::report_errors();
116223
}

0 commit comments

Comments
 (0)