On Thu, Apr 2, 2026 at 1:39 PM Jonathan Wakely <[email protected]> wrote:
> On Thu, 2 Apr 2026 at 11:43, Tomasz Kamiński <[email protected]> wrote: > > > > This paper removes the try_append_range from inplace_vector and changes > the > > return type of try_emplace_back and try_push_back to optional<_Tp&> per: > > P4022R0: Remove try_append_range from inplace_vector for now. > > P3981R2: Better return types in std::inplace_vector and > std::exception_ptr_cast. > > > > The test are also expanded to cover type Y, that is convertible to > optional<Y&>, > > and require return type to be constructed using in_place. > > > > libstdc++-v3/ChangeLog: > > > > * include/bits/version.def (inplace_vector): Bump to 202603. > > * include/bits/version.h: Regenerate. > > * include/std/inplace_vector (inplace_vector::try_emplace_back) > > (inplace_vector::try_push_back): Change return type to > optional<_Tp&> > > and adjust implementation accordingly. > > (inplace_vector::try_append_range): Remove. > > * include/debug/inplace_vector (inplace_vector::try_emplace_back) > > (inplace_vector::try_push_back, > inplace_vector::try_append_range): > > Likewise. > > * > testsuite/23_containers/inplace_vector/modifiers/single_insert.cc: > > Updated check for the optional<T&> return. Added test for type > > convertible to optional<T&> > > * > testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc: > > Use has_value() to check if engaged optional is returned. > > * > testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc: > > Likewise. > > * > testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc: > > Remove try_append_range tests. > > * > testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc: > > Removed. > > * testsuite/23_containers/inplace_vector/version.cc: Updated > expected > > feature test macro value. > > --- > > The exception_ptr change need to be handled seprately, due it being > > defined in libsup++. > > > > Testing on x86_64-linux. All *inplace_vector* test already passed. > > OK for trunk if all test finishes? > > > > libstdc++-v3/include/bits/version.def | 5 +- > > libstdc++-v3/include/bits/version.h | 4 +- > > libstdc++-v3/include/debug/inplace_vector | 26 ++----- > > libstdc++-v3/include/std/inplace_vector | 70 +++++-------------- > > .../debug/invalidation/try_append_range.cc | 45 ------------ > > .../debug/invalidation/try_emplace_back.cc | 2 +- > > .../debug/invalidation/try_push_back.cc | 4 +- > > .../inplace_vector/modifiers/multi_insert.cc | 46 ------------ > > .../inplace_vector/modifiers/single_insert.cc | 41 ++++++++--- > > .../23_containers/inplace_vector/version.cc | 4 +- > > 10 files changed, 66 insertions(+), 181 deletions(-) > > delete mode 100644 > libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc > > > > diff --git a/libstdc++-v3/include/bits/version.def > b/libstdc++-v3/include/bits/version.def > > index ada8da88bc5..998223306e2 100644 > > --- a/libstdc++-v3/include/bits/version.def > > +++ b/libstdc++-v3/include/bits/version.def > > @@ -2223,9 +2223,12 @@ ftms = { > > }; > > > > ftms = { > > + // 202406 P0843R14 inplace_vector > > + // 202603 P3981R2 Better return types in std::inplace_vector and > std::exception_ptr_cast > > + // P4022R0 Remove try_append_range from inplace_vector for now > > name = inplace_vector; > > values = { > > - v = 202406; > > + v = 202603; > > cxxmin = 26; > > }; > > }; > > diff --git a/libstdc++-v3/include/bits/version.h > b/libstdc++-v3/include/bits/version.h > > index 0490e79dd41..cb3b9b0997e 100644 > > --- a/libstdc++-v3/include/bits/version.h > > +++ b/libstdc++-v3/include/bits/version.h > > @@ -2488,9 +2488,9 @@ > > > > #if !defined(__cpp_lib_inplace_vector) > > # if (__cplusplus > 202302L) > > -# define __glibcxx_inplace_vector 202406L > > +# define __glibcxx_inplace_vector 202603L > > # if defined(__glibcxx_want_all) || > defined(__glibcxx_want_inplace_vector) > > -# define __cpp_lib_inplace_vector 202406L > > +# define __cpp_lib_inplace_vector 202603L > > # endif > > # endif > > #endif /* !defined(__cpp_lib_inplace_vector) */ > > diff --git a/libstdc++-v3/include/debug/inplace_vector > b/libstdc++-v3/include/debug/inplace_vector > > index 750b0a7343c..e579e8636f9 100644 > > --- a/libstdc++-v3/include/debug/inplace_vector > > +++ b/libstdc++-v3/include/debug/inplace_vector > > @@ -338,11 +338,12 @@ namespace __debug > > } > > > > template<typename... _Args> > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_emplace_back(_Args&&... __args) > > { > > auto __end = _Base::cend(); > > - _Tp* __res = > _Base::try_emplace_back(std::forward<_Args>(__args)...); > > + optional<_Tp&> __res > > + = _Base::try_emplace_back(std::forward<_Args>(__args)...); > > Is it valuable to state the type explicitly, rather than just using auto? > I like using `auto*` for pointers, instead of just auto, and the code was even more explicit before, so I matched the style. I think it helps, but that may be novelty of optional<_Tp&>. > > I don't have a preference, so OK for trunk either way. > I will keep it as is then. > > > > > if (__res) > > this->_M_invalidate_if(_Equal(__end)); > > @@ -350,11 +351,11 @@ namespace __debug > > return __res; > > } > > > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_push_back(const _Tp& __x) > > { > > const auto __end = _Base::cend(); > > - _Tp* __res = _Base::try_push_back(__x); > > + optional<_Tp&> __res = _Base::try_push_back(__x); > > > > if (__res) > > this->_M_invalidate_if(_Equal(__end)); > > @@ -362,11 +363,11 @@ namespace __debug > > return __res; > > } > > > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_push_back(_Tp&& __x) > > { > > const auto __end = _Base::cend(); > > - _Tp* __res = _Base::try_push_back(std::move(__x)); > > + optional<_Tp&> __res = _Base::try_push_back(std::move(__x)); > > > > if (__res) > > this->_M_invalidate_if(_Equal(__end)); > > @@ -374,19 +375,6 @@ namespace __debug > > return __res; > > } > > > > - template<__detail::__container_compatible_range<_Tp> _Rg> > > - constexpr ranges::borrowed_iterator_t<_Rg> > > - try_append_range(_Rg&& __rg) > > - { > > - const auto __size = size(); > > - const auto __end = _Base::cend(); > > - auto __res = _Base::try_append_range(__rg); > > - if (size() != __size) > > - this->_M_invalidate_if(_Equal(__end)); > > - > > - return __res; > > - } > > - > > template<typename... _Args> > > constexpr _Tp& > > unchecked_emplace_back(_Args&&... __args) > > diff --git a/libstdc++-v3/include/std/inplace_vector > b/libstdc++-v3/include/std/inplace_vector > > index c22a9e1f9b4..5ad92332a02 100644 > > --- a/libstdc++-v3/include/std/inplace_vector > > +++ b/libstdc++-v3/include/std/inplace_vector > > @@ -38,6 +38,7 @@ > > #ifdef __glibcxx_inplace_vector // C++ >= 26 > > #include <compare> > > #include <initializer_list> > > +#include <optional> > > #include <bits/stdexcept_throw.h> > > #include <bits/range_access.h> > > #include <bits/ranges_base.h> // borrowed_iterator_t, > __detail::__container_compatible_range > > @@ -550,63 +551,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER > > } > > > > template<typename... _Args> > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_emplace_back(_Args&&... __args) > > { > > if (_M_size >= _Nm) [[unlikely]] > > - return nullptr; > > - auto& __r = > unchecked_emplace_back(std::forward<_Args>(__args)...); > > - return __builtin_addressof(__r); > > + return nullopt; > > + return optional<_Tp&>(in_place, > > + > unchecked_emplace_back(std::forward<_Args>(__args)...)); > > } > > > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_push_back(const _Tp& __x) > > { > > if (_M_size >= _Nm) [[unlikely]] > > - return nullptr; > > - return __builtin_addressof(unchecked_emplace_back(__x)); > > + return nullopt; > > + return optional<_Tp&>(in_place, unchecked_emplace_back(__x)); > > } > > > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_push_back(_Tp&& __x) > > { > > if (_M_size >= _Nm) [[unlikely]] > > - return nullptr; > > - return > __builtin_addressof(unchecked_emplace_back(std::move(__x))); > > + return nullopt; > > + return optional<_Tp&>(in_place, > unchecked_emplace_back(std::move(__x))); > > } > > > > - template<__detail::__container_compatible_range<_Tp> _Rg> > > - constexpr ranges::borrowed_iterator_t<_Rg> > > - try_append_range(_Rg&& __rg) > > - { > > - if constexpr (ranges::sized_range<_Rg>) > > - { > > - auto __n = ranges::distance(__rg); > > - if (__n == 0) [[unlikely]] > > - return ranges::begin(__rg); > > - > > - const auto __end = data() + _M_size; > > - const size_t __avail = _Nm - size(); > > - if (__n <= __avail) > > - _M_size += size_type(__n); > > - else > > - { > > - __n = __avail; > > - _M_size = _Nm; > > - } > > - return ranges::uninitialized_copy_n( > > - ranges::begin(__rg), __n, > > - __end, unreachable_sentinel).in; > > - } > > - else > > - { > > - ranges::subrange<pointer> __tail(data() + _M_size, data() > + _Nm); > > - auto [__in, __out] = ranges::uninitialized_copy(__rg, > __tail); > > - _M_size = __out - data(); > > - return std::move(__in); > > - } > > - } > > - > > template<typename... _Args> > > constexpr _Tp& > > unchecked_emplace_back(_Args&&... __args) > > @@ -1208,22 +1177,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER > > { __builtin_trap(); } > > > > template<typename... _Args> > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_emplace_back(_Args&&...) > > - { return nullptr; } > > + { return nullopt; } > > > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_push_back(const _Tp&) > > - { return nullptr; } > > + { return nullopt; } > > > > - constexpr _Tp* > > + constexpr optional<_Tp&> > > try_push_back(_Tp&&) > > - { return nullptr; } > > - > > - template<__detail::__container_compatible_range<_Tp> _Rg> > > - constexpr ranges::borrowed_iterator_t<_Rg> > > - try_append_range(_Rg&& __rg) > > - { return ranges::begin(__rg); } > > + { return nullopt; } > > > > template<typename... _Args> > > [[noreturn]] > > diff --git > a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc > b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc > > deleted file mode 100644 > > index ae4ac418f50..00000000000 > > --- > a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc > > +++ /dev/null > > @@ -1,45 +0,0 @@ > > -// { dg-do run { target c++26 } } > > - > > -#include <debug/inplace_vector> > > -#include <testsuite_hooks.h> > > - > > -using __gnu_debug::inplace_vector; > > - > > -void test01() > > -{ > > - inplace_vector<int, 100> v(10, 17); > > - inplace_vector<int, 10> v1(10, 19); > > - > > - auto before = v.begin() + 6; > > - auto last = v.end(); > > - auto end = last--; > > - > > - v.try_append_range(v1); > > - > > - VERIFY(before._M_dereferenceable()); > > - VERIFY(last._M_dereferenceable()); > > - VERIFY(end._M_singular()); > > -} > > - > > -void test02() > > -{ > > - inplace_vector<int, 100> v(10, 17); > > - inplace_vector<int, 0> v1; > > - > > - auto before = v.begin() + 6; > > - auto last = v.end(); > > - auto end = last--; > > - > > - v.try_append_range(v1); > > - > > - VERIFY(before._M_dereferenceable()); > > - VERIFY(last._M_dereferenceable()); > > - VERIFY(!end._M_singular()); > > -} > > - > > -int main() > > -{ > > - test01(); > > - test02(); > > - return 0; > > -} > > diff --git > a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc > b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc > > index f7c8c7a9ba2..606d478a0dc 100644 > > --- > a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc > > +++ > b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc > > @@ -13,7 +13,7 @@ void test01() > > auto last = v.end(); > > auto end = last--; > > > > - VERIFY( v.try_emplace_back(42) != nullptr ); > > + VERIFY( v.try_emplace_back(42).has_value() ); > > > > VERIFY(before._M_dereferenceable()); > > VERIFY(last._M_dereferenceable()); > > diff --git > a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc > b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc > > index 04fc010e500..96af2b65b72 100644 > > --- > a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc > > +++ > b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc > > @@ -14,7 +14,7 @@ void test01() > > auto last = v.end(); > > auto end = last--; > > > > - VERIFY( v.try_push_back(42) != nullptr ); > > + VERIFY( v.try_push_back(42).has_value() ); > > > > VERIFY(before._M_dereferenceable()); > > VERIFY(last._M_dereferenceable()); > > @@ -30,7 +30,7 @@ void test02() > > auto last = v.end(); > > auto end = last--; > > > > - VERIFY( v.try_push_back(std::move(vv)) != nullptr ); > > + VERIFY( v.try_push_back(std::move(vv)).has_value() ); > > > > VERIFY(before._M_dereferenceable()); > > VERIFY(last._M_dereferenceable()); > > diff --git > a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc > b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc > > index 454163892ad..e5a482cdc65 100644 > > --- > a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc > > +++ > b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc > > @@ -54,16 +54,6 @@ test_add_to_full_it() > > > > std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N)); > > > > - Range r1(a, a); > > - auto rit1 = v.try_append_range(r1); > > - VERIFY( eq<T>(v, {a, N}) ); > > - VERIFY( rit1.base() == a ); > > - > > - SizedRange r2(a, a); > > - auto rit2 = v.try_append_range(r2); > > - VERIFY( eq<T>(v, {a, N}) ); > > - VERIFY( rit2.base() == a ); > > - > > v.append_range(Range(a, a)); > > VERIFY( eq<T>(v, {a, N}) ); > > v.append_range(SizedRange(a, a)); > > @@ -93,17 +83,6 @@ test_add_to_full_it() > > VERIFY( eq<T>(v, {a, N}) ); > > VERIFY( it == v.begin() ); > > > > - // Inserting non-empty range > > - Range r3(a+3, a+5); > > - auto rit3 = v.try_append_range(r3); > > - VERIFY( eq<T>(v, {a, N}) ); > > - VERIFY( rit3.base() == a+3 ); > > - > > - SizedRange r4(a+2, a+5); > > - auto rit4 = v.try_append_range(r4); > > - VERIFY( eq<T>(v, {a, N}) ); > > - VERIFY( rit4.base() == a+2 ); > > - > > #ifdef __cpp_exceptions > > #ifndef __cpp_lib_constexpr_exceptions > > if consteval { > > @@ -265,30 +244,6 @@ test_append_range() > > #endif > > } > > > > -template<typename Range> > > -constexpr void > > -test_try_append_range() > > -{ > > - using T = std::ranges::range_value_t<Range>; > > - T > a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25}; > > - > > - std::inplace_vector<T, 20> v; > > - Range r1 = Range(a, a+10); > > - auto it1 = v.try_append_range(r1); > > - VERIFY( eq<T>(v, {a, 10}) ); > > - VERIFY( it1.base() == a+10 ); > > - > > - Range r2 = Range(a+10, a+15); > > - auto it2 = v.try_append_range(r2); > > - VERIFY( eq<T>(v, {a, 15}) ); > > - VERIFY( it2.base() == a+15 ); > > - > > - Range r3 = Range(a+15, a+25); > > - auto it3 = v.try_append_range(r3); > > - VERIFY( eq<T>(v, {a, 20}) ); > > - VERIFY( it3.base() == a+20 ); > > -} > > - > > template<typename Range> > > constexpr void > > test_insert_range() > > @@ -357,7 +312,6 @@ constexpr void > > do_test_ranges() > > { > > test_append_range<Range>(); > > - test_try_append_range<Range>(); > > test_insert_range<Range>(); > > } > > > > diff --git > a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc > b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc > > index 92bd765982e..245af928800 100644 > > --- > a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc > > +++ > b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc > > @@ -3,6 +3,7 @@ > > #include <inplace_vector> > > > > #include <span> > > +#include <optional> > > #include <testsuite_hooks.h> > > > > struct X > > @@ -18,6 +19,20 @@ struct X > > friend auto operator<=>(const X&, const X&) = default; > > }; > > > > +// Type that is convertible to optional<Y&> > > +struct Y > > +{ > > + Y() = default; > > + constexpr Y(int p) : v(p) {} > > + > > + constexpr operator std::optional<Y&>() > > + { return std::nullopt; } > > + > > + int v; > > + > > + friend auto operator<=>(const Y&, const Y&) = default; > > +}; > > + > > template<typename T, typename V, size_t N> > > constexpr bool > > eq(const std::inplace_vector<V, N>& l, std::span<const T> r) { > > @@ -40,11 +55,11 @@ test_add_to_full() > > > > std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N)); > > > > - VERIFY( v.try_emplace_back(1) == nullptr ); > > + VERIFY( !v.try_emplace_back(1).has_value() ); > > VERIFY( eq<T>(v, {a, N}) ); > > - VERIFY( v.try_push_back(T(1)) == nullptr ); > > + VERIFY( !v.try_push_back(T(1)).has_value() ); > > VERIFY( eq<T>(v, {a, N}) ); > > - VERIFY( v.try_push_back(c) == nullptr ); > > + VERIFY( !v.try_push_back(c).has_value() ); > > VERIFY( eq<T>(v, {a, N}) ); > > > > #ifdef __cpp_exceptions > > @@ -149,15 +164,18 @@ test_inserts() > > v.unchecked_push_back(c); > > VERIFY( eq<T>(v, {a+3, 6}) ); > > > > - T* ptr = v.try_emplace_back(7); > > + std::optional<T&> opt = v.try_emplace_back(7); > > VERIFY( eq<T>(v, {a+3, 7}) ); > > - VERIFY( ptr = &v.back() ); > > - ptr = v.try_push_back(T(8)); > > + VERIFY( opt.has_value() ); > > + VERIFY( &*opt == &v.back() ); > > + opt = v.try_push_back(T(8)); > > VERIFY( eq<T>(v, {a+3, 8}) ); > > - VERIFY( ptr = &v.back() ); > > - ptr = v.try_push_back(c); > > + VERIFY( opt.has_value() ); > > + VERIFY( &*opt == &v.back() ); > > + opt = v.try_push_back(c); > > VERIFY( eq<T>(v, {a+3, 9}) ); > > - VERIFY( ptr = &v.back() ); > > + VERIFY( opt.has_value() ); > > + VERIFY( &*opt == &v.back() ); > > > > auto it = v.emplace(v.end(), 10); > > VERIFY( eq<T>(v, {a+3, 10}) ); > > @@ -195,12 +213,15 @@ int main() > > auto test_all = [] { > > test_add_to_full<0, int>(); > > test_add_to_full<0, X>(); > > + test_add_to_full<0, Y>(); > > > > test_add_to_full<4, int>(); > > + test_add_to_full<4, Y>(); > > > > test_inserts<int>(); > > + test_inserts<Y>(); > > #ifdef __cpp_lib_constexpr_inplace_vector > > -#error uncomemnt test_inserts<X>() > > +#error enable tests bellow > > #endif > > if ! consteval { > > test_add_to_full<4, X>(); > > diff --git > a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc > b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc > > index a5bbdb8464b..493e86dc6dd 100644 > > --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc > > +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc > > @@ -5,7 +5,7 @@ > > > > #ifndef __cpp_lib_inplace_vector > > # error "Feature-test macro for inplace_vector missing in > <inplace_vector>" > > -#elif __cpp_lib_inplace_vector != 202406L > > +#elif __cpp_lib_inplace_vector != 202603L > > # error "Feature-test macro for inplace_vector has wrong value in > <inplace_vector>" > > #endif > > > > @@ -15,6 +15,6 @@ > > > > #ifndef __cpp_lib_inplace_vector > > # error "Feature-test macro for inplace_vector missing in <version>" > > -#elif __cpp_lib_inplace_vector != 202406L > > +#elif __cpp_lib_inplace_vector != 202603L > > # error "Feature-test macro for inplace_vector has wrong value in > <version>" > > #endif > > -- > > 2.53.0 > > > >
