On Mon, May 19, 2025 at 11:28 PM Nathan Myers <n...@cantrip.org> wrote: In the title, we usually put link to bugzilla *PR119741* <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119741> in your case, not the paper. Then link the paper in commit descritpion.
Add constructors to stringbuf, stringstream, istringstream, > and ostringstream, and a matching overload of str(sv) in each, > that take anything convertible to a string_view where the > existing functions take a string. > After you put bugzilla number, git gcc-verify will suggest you to add following node: <tab>PR libstdc++/*119741* <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119741> > > libstdc++-v3/ChangeLog: > > P2495R3 stringstream to init from string_view-ish > We usually put only the change files here. Did git gcc-verify accepted it. > * include/std/sstream: full implementation, really just > decls, requires clause and plumbing. > * include/std/bits/version.def, .h: new preprocessor symbol > __cpp_lib_sstream_from_string_view. > * testsuite/27_io/basic_stringbuf/cons/char/3.cc: New tests. > * testsuite/27_io/basic_istringstream/cons/char/2.cc: New tests. > * testsuite/27_io/basic_ostringstream/cons/char/4.cc: New tests. > * testsuite/27_io/basic_stringstream/cons/char/2.cc: New tests. > --- > libstdc++-v3/ChangeLog | 11 + > libstdc++-v3/include/bits/version.def | 11 +- > libstdc++-v3/include/bits/version.h | 10 + > libstdc++-v3/include/std/sstream | 181 +++++++++++++-- > .../27_io/basic_istringstream/cons/char/2.cc | 193 ++++++++++++++++ > .../27_io/basic_ostringstream/cons/char/4.cc | 193 ++++++++++++++++ > .../27_io/basic_stringbuf/cons/char/3.cc | 216 ++++++++++++++++++ > .../27_io/basic_stringstream/cons/char/2.cc | 194 ++++++++++++++++ > 8 files changed, 990 insertions(+), 19 deletions(-) > create mode 100644 > libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc > create mode 100644 > libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc > create mode 100644 > libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc > create mode 100644 > libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc > > diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog > index b45f8c2c7a5..ac0ff4a386f 100644 > --- a/libstdc++-v3/ChangeLog > +++ b/libstdc++-v3/ChangeLog > @@ -41,6 +41,17 @@ > PR libstdc++/119246 > * include/std/format: Updated check for _GLIBCXX_FORMAT_F128. > > +2025-05-14 Nathan Myers <nmy...@redhat.com> > + P2495R3 stringstream to init from string_view-ish > + * include/std/sstream: full implementation, really just > + decls, requires clause and plumbing. > + * include/std/bits/version.def, .h: new preprocessor symbol > + __cpp_lib_sstream_from_string_view. > + * testsuite/27_io/basic_stringbuf/cons/char/3.cc: New tests. > + * testsuite/27_io/basic_istringstream/cons/char/2.cc: New tests. > + * testsuite/27_io/basic_ostringstream/cons/char/4.cc: New tests. > + * testsuite/27_io/basic_stringstream/cons/char/2.cc: New tests. > + > Changelogs are now automatically generated from commit messages, so you do not need to edit this file. > 2025-05-14 Tomasz Kamiński <tkami...@redhat.com> > > PR libstdc++/119125 > diff --git a/libstdc++-v3/include/bits/version.def > b/libstdc++-v3/include/bits/version.def > index 6ca148f0488..567c56b4117 100644 > --- a/libstdc++-v3/include/bits/version.def > +++ b/libstdc++-v3/include/bits/version.def > @@ -649,7 +649,7 @@ ftms = { > }; > values = { > v = 1; > - /* For when there's no gthread. */ > + // For when there is no gthread. > cxxmin = 17; > hosted = yes; > gthread = no; > @@ -1961,6 +1961,15 @@ ftms = { > }; > }; > > +ftms = { > + name = sstream_from_string_view; > + values = { > + v = 202302; > + cxxmin = 26; > + hosted = yes; > + }; > +}; > + > // Standard test specifications. > stds[97] = ">= 199711L"; > stds[03] = ">= 199711L"; > diff --git a/libstdc++-v3/include/bits/version.h > b/libstdc++-v3/include/bits/version.h > index 48a090c14a3..5d1beb83a25 100644 > --- a/libstdc++-v3/include/bits/version.h > +++ b/libstdc++-v3/include/bits/version.h > @@ -2193,4 +2193,14 @@ > #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) > */ > #undef __glibcxx_want_modules > > +#if !defined(__cpp_lib_sstream_from_string_view) > +# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED > +# define __glibcxx_sstream_from_string_view 202302L > +# if defined(__glibcxx_want_all) || > defined(__glibcxx_want_sstream_from_string_view) > +# define __cpp_lib_sstream_from_string_view 202302L > +# endif > +# endif > +#endif /* !defined(__cpp_lib_sstream_from_string_view) && > defined(__glibcxx_want_sstream_from_string_view) */ > +#undef __glibcxx_want_sstream_from_string_view > + > #undef __glibcxx_want_all > diff --git a/libstdc++-v3/include/std/sstream > b/libstdc++-v3/include/std/sstream > index ad0c16a91e8..9b2b0eb53fc 100644 > --- a/libstdc++-v3/include/std/sstream > +++ b/libstdc++-v3/include/std/sstream > @@ -38,9 +38,14 @@ > #endif > > #include <bits/requires_hosted.h> // iostream > +#include <bits/version.h> > > #include <istream> > #include <ostream> > +#ifdef __cpp_lib_sstream_from_string_view > +# include <type_traits> // is_convertible_v > +#endif > + > #include <bits/alloc_traits.h> // allocator_traits, __allocator_like > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > @@ -52,8 +57,6 @@ > # define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]] > #endif > > - > - > namespace std _GLIBCXX_VISIBILITY(default) > { > _GLIBCXX_BEGIN_NAMESPACE_VERSION > @@ -159,6 +162,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, > 0); } > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > + // P0408 Efficient access to basic_stringbuf buffer > explicit > basic_stringbuf(const allocator_type& __a) > : basic_stringbuf(ios_base::in | std::ios_base::out, __a) > @@ -197,7 +201,35 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > | ios_base::out) > : basic_stringbuf(__s, __mode, allocator_type{}) > { } > +#endif > + > +#ifdef __cpp_lib_sstream_from_string_view > + template<typename _Tp> > + explicit > + basic_stringbuf(const _Tp& __t, ios_base::openmode __mode = > ios_base::in | ios_base::out) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_stringbuf(__t, __mode, allocator_type{}) > + { } > + > + template<typename _Tp> > + basic_stringbuf(const _Tp& __t, const allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_stringbuf(__t, ios_base::in | ios_base::out, __a) > + { } > > + template<typename _Tp> > + basic_stringbuf(const _Tp& __t, ios_base::openmode __mode, const > allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_stringbuf(__mode, __a) > Any reason for not initializing _M_string(t, __a) directly here, string has string_view constructor. > + { > + basic_string_view<_CharT, _Traits> __sv{__t}; > + _M_string = __sv; > + _M_stringbuf_init(__mode); > + } > +#endif // C++26 > + > +#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > + // P0408 Efficient access to basic_stringbuf buffer > basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a) > : basic_stringbuf(std::move(__rhs), __a, __xfer_bufptrs(__rhs, > this)) > { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, > 0); } > @@ -262,6 +294,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > #if __cplusplus > 201703L > #if _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > _GLIBCXX_NODISCARD > basic_string<_CharT, _Traits, _SAlloc> > @@ -317,6 +350,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > requires (!is_same_v<_SAlloc, _Alloc>) > void > @@ -335,6 +369,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > } > #endif > > +#ifdef __cpp_lib_sstream_from_string_view > + template <typename _Tp> > + void > + str(const _Tp& __t) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + { > + basic_string_view<_CharT, _Traits> __sv{__t}; > + _M_string = __sv; > + _M_stringbuf_init(_M_mode); > + } > +#endif // C++26 > + > protected: > // Common initialization code goes here. > void > @@ -521,6 +567,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > { } > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > + // P0408 Efficient access to basic_stringbuf buffer > + > // The move constructor initializes an __xfer_bufptrs temporary then > // delegates to this constructor to performs moves during its > lifetime. > basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a, > @@ -584,7 +632,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > */ > basic_istringstream() > : __istream_type(), _M_stringbuf(ios_base::in) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief Starts with an empty string buffer. > @@ -601,7 +649,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > explicit > basic_istringstream(ios_base::openmode __mode) > : __istream_type(), _M_stringbuf(__mode | ios_base::in) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief Starts with an existing string buffer. > @@ -620,7 +668,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > basic_istringstream(const __string_type& __str, > ios_base::openmode __mode = ios_base::in) > : __istream_type(), _M_stringbuf(__str, __mode | ios_base::in) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief The destructor does nothing. > @@ -637,9 +685,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > basic_istringstream(basic_istringstream&& __rhs) > : __istream_type(std::move(__rhs)), > _M_stringbuf(std::move(__rhs._M_stringbuf)) > - { __istream_type::set_rdbuf(&_M_stringbuf); } > + { __istream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > + // P0408 Efficient access to basic_stringbuf buffer > basic_istringstream(ios_base::openmode __mode, const > allocator_type& __a) > : __istream_type(), _M_stringbuf(__mode | ios_base::in, __a) > { this->init(std::__addressof(_M_stringbuf)); } > @@ -667,10 +716,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > explicit > basic_istringstream(const basic_string<_CharT, _Traits, _SAlloc>& > __str, > ios_base::openmode __mode = ios_base::in) > +#ifdef __cpp_lib_sstream_from_string_view > + requires (!is_same_v<_SAlloc, allocator_type>) > +#endif // C++26 > Standard have same constraint of ostringstream ( https://eel.is/c++draft/string.streams#ostringstream.cons-6): *Constraints*: is_same_v<SAlloc,Allocator> is false. Do we miss some library issue? : basic_istringstream(__str, __mode, allocator_type()) > { } > #endif // C++20 > > +#ifdef __cpp_lib_sstream_from_string_view > + template <typename _Tp> > + explicit basic_istringstream(const _Tp& __t, ios_base::openmode > __mode = ios_base::in) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_istringstream(__t, __mode, allocator_type{}) > + { } > + > + template <typename _Tp> > + basic_istringstream(const _Tp& __t, const allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_istringstream(__t, ios_base::in, __a) > + { } > + > + template <typename _Tp> > + basic_istringstream(const _Tp& __t, ios_base::openmode __mode, > const allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : __istream_type(), _M_stringbuf(__t, __mode | ios_base::in, __a) > + { this->init(std::__addressof(_M_stringbuf)); } > +#endif // C++26 > + > // 27.8.3.2 Assign and swap: > > basic_istringstream& > @@ -702,7 +774,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > _GLIBCXX_NODISCARD > __stringbuf_type* > rdbuf() const > - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } > + { return > const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } > > /** > * @brief Copying out the string buffer. > @@ -716,6 +788,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > #if __cplusplus > 201703L > #if _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > _GLIBCXX_NODISCARD > basic_string<_CharT, _Traits, _SAlloc> > @@ -747,6 +820,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > requires (!is_same_v<_SAlloc, _Alloc>) > void > @@ -758,6 +832,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > str(__string_type&& __s) > { _M_stringbuf.str(std::move(__s)); } > #endif > + > +#ifdef __cpp_lib_sstream_from_string_view > + template<typename _Tp> > + void > + str(const _Tp& __t) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + { _M_stringbuf.str(__t); } > +#endif // C++26 > }; > > > @@ -812,7 +894,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > */ > basic_ostringstream() > : __ostream_type(), _M_stringbuf(ios_base::out) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief Starts with an empty string buffer. > @@ -829,7 +911,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > explicit > basic_ostringstream(ios_base::openmode __mode) > : __ostream_type(), _M_stringbuf(__mode | ios_base::out) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief Starts with an existing string buffer. > @@ -848,7 +930,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > basic_ostringstream(const __string_type& __str, > ios_base::openmode __mode = ios_base::out) > : __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief The destructor does nothing. > @@ -865,9 +947,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > basic_ostringstream(basic_ostringstream&& __rhs) > : __ostream_type(std::move(__rhs)), > _M_stringbuf(std::move(__rhs._M_stringbuf)) > - { __ostream_type::set_rdbuf(&_M_stringbuf); } > + { __ostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > + // P0408 Efficient access to basic_stringbuf buffer > basic_ostringstream(ios_base::openmode __mode, const > allocator_type& __a) > : __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a) > { this->init(std::__addressof(_M_stringbuf)); } > @@ -899,6 +982,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > { } > #endif // C++20 > > +#ifdef __cpp_lib_sstream_from_string_view > + template <typename _Tp> > + explicit basic_ostringstream(const _Tp& __t, ios_base::openmode > __mode = ios_base::out) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_ostringstream(__t, __mode, allocator_type{}) > + { } > + > + template <typename _Tp> > + basic_ostringstream(const _Tp& __t, const allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_ostringstream(__t, ios_base::out, __a) > + { } > + > + template <typename _Tp> > + basic_ostringstream(const _Tp& __t, ios_base::openmode __mode, > const allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : __ostream_type(), _M_stringbuf(__t, __mode | ios_base::out, __a) > + { this->init(std::__addressof(_M_stringbuf)); } > +#endif // C++26 > + > // 27.8.3.2 Assign and swap: > > basic_ostringstream& > @@ -930,7 +1033,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > _GLIBCXX_NODISCARD > __stringbuf_type* > rdbuf() const > - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } > + { return > const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } > > /** > * @brief Copying out the string buffer. > @@ -944,6 +1047,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > #if __cplusplus > 201703L > #if _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > _GLIBCXX_NODISCARD > basic_string<_CharT, _Traits, _SAlloc> > @@ -975,6 +1079,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > requires (!is_same_v<_SAlloc, _Alloc>) > void > @@ -986,6 +1091,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > str(__string_type&& __s) > { _M_stringbuf.str(std::move(__s)); } > #endif > + > +#ifdef __cpp_lib_sstream_from_string_view > + template<typename _Tp> > + void > + str(const _Tp& __t) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + { _M_stringbuf.str(__t); } > +#endif // C++26 > }; > > > @@ -1040,7 +1153,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > */ > basic_stringstream() > : __iostream_type(), _M_stringbuf(ios_base::out | ios_base::in) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief Starts with an empty string buffer. > @@ -1055,7 +1168,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > explicit > basic_stringstream(ios_base::openmode __m) > : __iostream_type(), _M_stringbuf(__m) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief Starts with an existing string buffer. > @@ -1072,7 +1185,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > basic_stringstream(const __string_type& __str, > ios_base::openmode __m = ios_base::out | > ios_base::in) > : __iostream_type(), _M_stringbuf(__str, __m) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > /** > * @brief The destructor does nothing. > @@ -1089,12 +1202,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > basic_stringstream(basic_stringstream&& __rhs) > : __iostream_type(std::move(__rhs)), > _M_stringbuf(std::move(__rhs._M_stringbuf)) > - { __iostream_type::set_rdbuf(&_M_stringbuf); } > + { __iostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > + // P0408 Efficient access to basic_stringbuf buffer > basic_stringstream(ios_base::openmode __mode, const allocator_type& > __a) > : __iostream_type(), _M_stringbuf(__mode, __a) > - { this->init(&_M_stringbuf); } > + { this->init(std::__addressof(_M_stringbuf)); } > > explicit > basic_stringstream(__string_type&& __str, > @@ -1125,6 +1239,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > { } > #endif // C++20 > > +#ifdef __cpp_lib_sstream_from_string_view > + template <typename _Tp> > + explicit basic_stringstream(const _Tp& __t, > + ios_base::openmode __mode = > ios_base::in | ios_base::out) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_stringstream(__t, __mode, allocator_type{}) > + { } > + > + template <typename _Tp> > + basic_stringstream(const _Tp& __t, const allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : basic_stringstream(__t, ios_base::in | ios_base::out, __a) > + { } > + > + template <typename _Tp> > + basic_stringstream(const _Tp& __t, ios_base::openmode __mode, > const allocator_type& __a) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + : __iostream_type(), _M_stringbuf(__t, __mode, __a) > + { this->init(std::__addressof(_M_stringbuf)); } > +#endif // C++26 > + > // 27.8.3.2 Assign and swap: > > basic_stringstream& > @@ -1156,7 +1291,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > _GLIBCXX_NODISCARD > __stringbuf_type* > rdbuf() const > - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } > + { return > const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } > > /** > * @brief Copying out the string buffer. > @@ -1170,6 +1305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > #if __cplusplus > 201703L > #if _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > _GLIBCXX_NODISCARD > basic_string<_CharT, _Traits, _SAlloc> > @@ -1201,6 +1337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > #if __cpp_concepts > + // P0407 Allocator-aware basic_streambuf > template<__allocator_like _SAlloc> > requires (!is_same_v<_SAlloc, _Alloc>) > void > @@ -1212,6 +1349,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > str(__string_type&& __s) > { _M_stringbuf.str(std::move(__s)); } > #endif > + > +#ifdef __cpp_lib_sstream_from_string_view > + template<typename _Tp> > + void > + str(const _Tp& __t) > + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, > _Traits>>) > + { _M_stringbuf.str(__t); } > +#endif // C++26 > }; > > #if __cplusplus >= 201103L > diff --git > a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc > b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc > new file mode 100644 > index 00000000000..4c27ad2ea07 > --- /dev/null > +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc > @@ -0,0 +1,193 @@ > +// C++26 [istringstream.general] > + > +// { dg-do run { target c++26 } } > +// { dg-require-effective-target cxx11_abi } > + > +#include <sstream> > +#include <string> > +#include <string_view> > +#include <testsuite_allocator.h> > +#include <testsuite_hooks.h> > + > +// Check C++26 P2495 istringstream ctors and members str(s) that accept a > +// string_view, or anything convertible to a string_view, in place of a > +// string object. Mostly just verify plumbing. > + > +struct convertible_to_string_view { > + std::string s; > + operator std::string_view() const { return s; } > +}; > + > +const std::string str("This is a test string"); > +convertible_to_string_view cstr{str}; // a copy > +const convertible_to_string_view ccstr{str}; // another copy > + > +template <typename istringstream = std::basic_istringstream<char>> > +void > +test01() > +{ > + // Test C++26 constructor and str(s) taking a generalized string_view > + > + static_assert(! requires { istringstream(1); }, > + "istringstream ctor should reject what cannot be converted to a > string_view"); > + static_assert(! requires { istringstream().str(1); }, > + "istringstream::str(s) should reject what cannot be converted to a > string_view"); > + > + static_assert(!std::is_convertible_v<std::string_view, > std::istringstream>, > + "istringstream(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<const std::string_view, > std::istringstream>, > + "istringstream(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<convertible_to_string_view, > std::istringstream>, > + "istringstream(convertible_to_string_view, ios::openmode) is > explicit"); > + static_assert(!std::is_convertible_v<const convertible_to_string_view, > std::istringstream>, > + "istringstream(convertible_to_string_view, ios::openmode) is > explicit"); > + > + { > + std::istringstream istr(cstr); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + } > + { > + std::istringstream istr(ccstr); > + VERIFY( istr.str() == ccstr.s ); > + VERIFY( istr.get() == ccstr.s[0] ); > + } > + { > + std::istringstream istr(cstr, std::ios_base::in); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > + } > + { > + std::istringstream istr(cstr, std::ios_base::out); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); > + } > +} > + > +void > +test02() > +{ > + // Test C++26 constructors taking string views using different > allocators > + > + using alloc_type = __gnu_test::tracker_allocator<char>; > I would use __gnu_test::uneq_allocator<>, as it have state (int), that is checked in equality in VERIFY. > + using str_type = std::basic_string<char, std::char_traits<char>, > alloc_type>; > + > + auto const mode = std::ios_base::in | std::ios_base::out; > + > + { > + // template <typename T> > + // basic_istringstream(const T&, ios_base::openmode, const > allocator_type&) > + > + std::istringstream::allocator_type a; > + { > + std::istringstream istr(cstr, mode, a); // ={} checks for > non-explicit ctor > + VERIFY( istr.str() == cstr.s ); > + } > + { > + std::istringstream istr(cstr, std::ios::in, a); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > + } > + { > + std::istringstream istr(cstr, std::ios::out, a); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); > + } > + } > + > + { > + // template <typename T> > + // basic_istringstream(const T&, ios_base::openmode) > + { > + std::istringstream istr(cstr, mode); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); > + } > + { > + std::istringstream istr(cstr, std::ios::in); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > + } > + { > + std::istringstream istr(cstr, std::ios::out); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); > + } > + } > + > + { > + // template <typename T> > + // explicit > + // basic_istringstream(const T&, ios_base::openmode = ios_base::in) > + > + std::istringstream istr(cstr); > + VERIFY( istr.str() == cstr.s ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > + } > +} > + > +// A minimal allocator with no default constructor > +template<typename T> > + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> > + { > + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; > + NoDefaultCons() = delete; > + NoDefaultCons(int) { } > + }; > + > +template<typename Alloc, typename C = typename Alloc::value_type> > + using istringstream_with_alloc > + = std::basic_istringstream<C, std::char_traits<C>, Alloc>; > + > +void test03() > +{ > + NoDefaultCons<char> a{1}; > + { > + istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, a); > + VERIFY( std::string_view{istr.str()} == cstr ); > + VERIFY( istr.get() == cstr.s[0] ); > + } > + { > + istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, > std::ios::in, a); > + VERIFY( std::string_view{istr.str()} == cstr ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > + } > + { > + istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, > std::ios::out, a); > + VERIFY( std::string_view{istr.str()} == cstr ); > + VERIFY( istr.get() == cstr.s[0] ); > + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); > + } > +} > + > +void test04() > +{ > + { > + std::istringstream istr; > + istr.str( cstr ); > + VERIFY( istr.str() == cstr.s ); > + } > + { > + std::istringstream istr; > + istr.str( ccstr ); > + VERIFY( istr.str() == ccstr.s ); > + } > +} > + > +int > +main() > +{ > + test01(); > + test02(); > + test03(); > + test04(); > +} > diff --git > a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc > b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc > new file mode 100644 > index 00000000000..1ca27dfbfa5 > --- /dev/null > +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc > @@ -0,0 +1,193 @@ > +// C++26 [ostringstream.general] > + > +// { dg-do run { target c++26 } } > +// { dg-require-effective-target cxx11_abi } > + > +#include <sstream> > +#include <string> > +#include <string_view> > +#include <testsuite_allocator.h> > +#include <testsuite_hooks.h> > + > +// Check C++26 P2495 ostringstream ctors and members str(s) that accept a > +// string_view, or anything convertible to a string_view, in place of a > +// string object. Mostly just verify plumbing. > + > +struct convertible_to_string_view { > + std::string s; > + operator std::string_view() const { return s; } > +}; > + > +const std::string str("This is a test string"); > +convertible_to_string_view cstr{str}; // a copy > +const convertible_to_string_view ccstr{str}; // another copy > + > +template <typename ostringstream = std::basic_ostringstream<char>> > +void > +test01() > +{ > + // Test C++26 constructor and str(s) taking a generalized string_view > + > + static_assert(! requires { ostringstream(1); }, > + "ostringstream ctor should reject what cannot be converted to a > string_view"); > + static_assert(! requires { ostringstream().str(1); }, > + "ostringstream::str(s) should reject what cannot be converted to a > string_view"); > + > + static_assert(!std::is_convertible_v<std::string_view, > std::ostringstream>, > + "ostringstream(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<const std::string_view, > std::ostringstream>, > + "ostringstream(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<convertible_to_string_view, > std::ostringstream>, > + "ostringstream(convertible_to_string_view, ios::openmode) is > explicit"); > + static_assert(!std::is_convertible_v<const convertible_to_string_view, > std::ostringstream>, > + "ostringstream(convertible_to_string_view, ios::openmode) is > explicit"); > + > + { > + std::ostringstream ostrstr(cstr); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + } > + { > + std::ostringstream ostrstr(ccstr); > + VERIFY( ostrstr.str() == ccstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + } > + { > + std::ostringstream ostrstr(cstr, std::ios_base::in); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > + } > + { > + std::ostringstream ostrstr(cstr, std::ios_base::out); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > + } > +} > + > +void > +test02() > +{ > + // Test C++26 constructors taking string views using different > allocators > + > + using alloc_type = __gnu_test::tracker_allocator<char>; > + using str_type = std::basic_string<char, std::char_traits<char>, > alloc_type>; > + > + auto const mode = std::ios_base::in | std::ios_base::out; > + > + { > + std::ostringstream::allocator_type a; > + // template <typename T> > + // basic_ostringstream(const T&, ios_base::openmode, const > allocator_type&) > + { > + std::ostringstream ostrstr(cstr, mode, a); // ={} checks for > non-explicit ctor > + VERIFY( ostrstr.str() == cstr.s ); > + } > + { > + std::ostringstream ostrstr(cstr, std::ios::in, a); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > + } > + { > + std::ostringstream ostrstr(cstr, std::ios::out, a); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > + } > + } > + > + { > + // template <typename T> > + // basic_ostringstream(const T&, ios_base::openmode) > + { > + std::ostringstream ostrstr(cstr, mode); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > + VERIFY( ostrstr.put('Y').good() ); > + } > + { > + std::ostringstream ostrstr(cstr, std::ios::in); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > + VERIFY( ostrstr.put('X').good() ); > + } > + { > + std::ostringstream ostrstr(cstr, std::ios::out); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > + } > + } > + > + { > + // template <typename T> > + // explicit > + // basic_ostringstream(const T&, ios_base::openmode = ios_base::out) > + > + std::ostringstream ostrstr(cstr); > + VERIFY( ostrstr.str() == cstr.s ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + VERIFY( ostrstr.put('Y').good() ); > + } > +} > + > +// A minimal allocator with no default constructor > +template<typename T> > + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> > + { > + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; > + NoDefaultCons() = delete; > + NoDefaultCons(int) { } > + }; > + > +template<typename Alloc, typename C = typename Alloc::value_type> > + using ostringstream_with_alloc > + = std::basic_ostringstream<C, std::char_traits<C>, Alloc>; > + > +void test03() > +{ > + NoDefaultCons<char> a{1}; > + { > + ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, a); > + VERIFY( std::string_view{ostrstr.str()} == cstr ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + VERIFY( ostrstr.put('X').good() ); > + } > + { > + ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, > std::ios::in, a); > + VERIFY( std::string_view{ostrstr.str()} == cstr ); > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > + VERIFY( ostrstr.put('X').good() ); > + } > + { > + ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, > std::ios::out, a); > + VERIFY( std::string_view{ostrstr.str()} == cstr ); > + VERIFY( ostrstr.rdbuf()->sgetc() == > std::stringbuf::traits_type::eof() ); > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > + } > +} > + > +void test04() > +{ > + { > + std::ostringstream ostrstr; > + ostrstr.str(cstr); > + VERIFY( ostrstr.str() == cstr.s ); > + } > + { > + std::ostringstream ostrstr; > + ostrstr.str(ccstr); > + VERIFY( ostrstr.str() == ccstr.s ); > + } > +} > + > +int > +main() > +{ > + test01(); > + test02(); > + test03(); > + test04(); > +} > diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc > b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc > new file mode 100644 > index 00000000000..35f544c1201 > --- /dev/null > +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc > @@ -0,0 +1,216 @@ > +// C++26 31.8.2.1 [stringbuf.general] > + > +// { dg-do run { target c++26 } } > +// { dg-require-effective-target cxx11_abi } > + > +#include <sstream> > +#include <string> > +#include <string_view> > +#include <testsuite_allocator.h> > +#include <testsuite_hooks.h> > + > +// Check C++26 P2495 stringbuf ctors and members str(s) that accept a > +// string_view, or anything convertible to a string_view, in place of a > +// string object. > + > +struct convertible_to_string_view { > + std::string s; > + operator std::string_view() const { return s; } > +}; > + > +struct convertible_to_both { > + std::string s; > + operator std::string_view() const { return s; } > + operator std::string() const { return s; } > +}; > + > +const std::string str("This is a test string"); > +convertible_to_string_view cstr{str}; // a copy > +const convertible_to_string_view ccstr{str}; // another copy > +convertible_to_both bcstr{str}; > + > +template <typename stringbuf = std::basic_stringbuf<char>> > +void > +test01() > +{ > + // Test C++26 constructor and str(s) taking a generalized string_view > + > + static_assert(! requires { stringbuf(1); }, > + "stringbuf ctor should reject what cannot be converted to a > string_view"); > + static_assert(! requires { stringbuf().str(1); }, > + "stringbuf::str(s) should reject what cannot be converted to a > string_view"); > + > + static_assert(!std::is_convertible_v<std::string_view, std::stringbuf>, > + "stringbuf(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<const std::string_view, > std::stringbuf>, > + "stringbuf(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<convertible_to_string_view, > std::stringbuf>, > + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<const convertible_to_string_view, > std::stringbuf>, > + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); > + > + { > + std::stringbuf sbuf(cstr); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > + } > + { // check from a const source object > + std::stringbuf sbuf(ccstr); > + VERIFY( sbuf.str() == ccstr.s ); > + VERIFY( sbuf.sgetc() == ccstr.s[0] ); > + } > + { // check from a type that has conversions to both std::string > + // and std::string_view > + std::stringbuf sbuf(bcstr); > + VERIFY( sbuf.str() == bcstr.s ); > + VERIFY( sbuf.sgetc() == ccstr.s[0] ); > + } > + { > + std::stringbuf sbuf(cstr, std::ios_base::in); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); > + } > + { > + std::stringbuf sbuf(ccstr, std::ios_base::in); > + VERIFY( sbuf.str() == ccstr.s ); > + VERIFY( sbuf.sgetc() == ccstr.s[0] ); > + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); > + } > + { > + std::stringbuf sbuf(cstr, std::ios_base::out); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sputc('Y') == 'Y' ); > + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); > + } > + { > + std::stringbuf sbuf(ccstr, std::ios_base::out); > + VERIFY( sbuf.str() == ccstr.s ); > + VERIFY( sbuf.sputc('Y') == 'Y' ); > + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); > + } > +} > + > +void > +test02() > +{ > + // Test C++26 constructors taking string views using different > allocators > + > + using alloc_type = __gnu_test::tracker_allocator<char>; > + using str_type = std::basic_string<char, std::char_traits<char>, > alloc_type>; > + > + auto const mode = std::ios_base::in | std::ios_base::out; > + > + { > + // template <typename T> > + // basic_stringbuf(const T&, ios_base::openmode, const > allocator_type&) > + > + std::stringbuf::allocator_type a; > + { > + std::stringbuf sbuf(cstr, mode, a); // ={} checks for non-explicit > ctor > + VERIFY( sbuf.str() == cstr.s ); > + } > + { > + std::stringbuf sbuf(cstr, std::ios::in, a); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); > + } > + > + { > + std::stringbuf sbuf(cstr, std::ios::out, a); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sputc('X') == 'X' ); > + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); > + } > + } > + > + { > + // template <typename T> > + // basic_stringbuf(const T&, ios_base::openmode) > + { > + std::stringbuf sbuf(cstr, mode); > + VERIFY( sbuf.str() == cstr.s ); > + } > + { > + std::stringbuf sbuf(cstr, std::ios::in); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); > + } > + { > + std::stringbuf sbuf(cstr, std::ios::out); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sputc('X') == 'X' ); > + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); > + } > + } > + > + { > + // template <typename T> > + // explicit > + // basic_stringbuf(const T&, ios_base::openmode = > ios_base::in|ios_base::out) > + > + std::stringbuf sbuf(cstr); > + VERIFY( sbuf.str() == cstr.s ); > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > + } > +} > + > +// A minimal allocator with no default constructor > +template<typename T> > + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> > + { > + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; > + NoDefaultCons() = delete; > + NoDefaultCons(int) { } > + }; > + > +template<typename Alloc, typename C = typename Alloc::value_type> > + using stringbuf_with_alloc > + = std::basic_stringbuf<C, std::char_traits<C>, Alloc>; > + > +void test03() > +{ > + NoDefaultCons<char> a{1}; > + { > + stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, a); > + VERIFY( std::string_view{sbuf.str()} == cstr ); > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > + } > + { > + stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, std::ios::in, a); > + VERIFY( std::string_view{sbuf.str()} == cstr ); > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > + VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() ); > + } > + { > + stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, std::ios::out, > a); > + VERIFY( std::string_view{sbuf.str()} == cstr ); > + VERIFY( sbuf.sputc('X') == 'X' ); > + VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() ); > + } > +} > + > +void test04() > +{ > + { > + std::stringbuf sbuf; > + sbuf.str(cstr); > + VERIFY( sbuf.str() == cstr.s ); > + } > + { > + std::stringbuf sbuf; > + sbuf.str(ccstr); > + VERIFY( sbuf.str() == ccstr.s ); > + } > +} > + > +int > +main() > +{ > + test01(); > + test02(); > + test03(); > + test04(); > +} > diff --git > a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc > b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc > new file mode 100644 > index 00000000000..06fab33a382 > --- /dev/null > +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc > @@ -0,0 +1,194 @@ > +// C++26 31.8.2.1 [stringstream.general] > + > +// { dg-do run { target c++26 } } > +// { dg-require-effective-target cxx11_abi } > + > +#include <sstream> > +#include <string> > +#include <string_view> > +#include <testsuite_allocator.h> > +#include <testsuite_hooks.h> > + > +// Check C++26 P2495 stringstream ctors and members str(s) that accept a > +// string_view, or anything convertible to a string_view, in place of a > +// string object. Mostly just verify plumbing. > + > +struct convertible_to_string_view { > + std::string s; > + operator std::string_view() const { return s; } > +}; > + > +const std::string str("This is a test string"); > +convertible_to_string_view cstr{str}; // a copy > +const convertible_to_string_view ccstr{str}; // another copy > + > +template <typename stringstream = std::basic_stringstream<char>> > +void > +test01() > +{ > + // Test C++26 constructor and str(s) taking a generalized string_view > + > + static_assert(! requires { stringstream(1); }, > + "stringstream ctor should reject what cannot be converted to a > string_view"); > + static_assert(! requires { stringstream().str(1); }, > + "stringstream::str(s) should reject what cannot be converted to a > string_view"); > + > + static_assert(!std::is_convertible_v<std::string_view, > std::stringstream>, > + "stringstream(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<const std::string_view, > std::stringstream>, > + "stringstream(string_view, ios::openmode) is explicit"); > + static_assert(!std::is_convertible_v<convertible_to_string_view, > std::stringstream>, > + "stringstream(convertible_to_string_view, ios::openmode) is > explicit"); > + static_assert(!std::is_convertible_v<const convertible_to_string_view, > std::stringstream>, > + "stringstream(convertible_to_string_view, ios::openmode) is > explicit"); > + > + { > + std::stringstream strstr(cstr); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.get() == cstr.s[0] ); > + } > + { > + std::stringstream strstr(ccstr); > + VERIFY( strstr.str() == ccstr.s ); > + VERIFY( strstr.get() == ccstr.s[0] ); > + } > + { > + std::stringstream strstr(cstr, std::ios_base::in); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.get() == cstr.s[0] ); > + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); > + } > + { > + std::stringstream strstr(cstr, std::ios_base::out); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.put('Y').good() ); > + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); > + } > +} > + > +void > +test02() > +{ > + // Test C++26 constructors taking string views using different > allocators > + > + using alloc_type = __gnu_test::tracker_allocator<char>; > + using str_type = std::basic_string<char, std::char_traits<char>, > alloc_type>; > + > + auto const mode = std::ios_base::in | std::ios_base::out; > + > + { > + // template <typename T> > + // basic_stringstream(const T&, ios_base::openmode, const > allocator_type&) > + > + std::stringstream::allocator_type a; > + { > + std::stringstream strstr(cstr, mode, a); // ={} checks for > non-explicit ctor > + VERIFY( strstr.str() == cstr.s ); > + } > + { > + std::stringstream strstr(cstr, std::ios::in, a); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.get() == cstr.s[0] ); > + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); > + } > + { > + std::stringstream strstr(cstr, std::ios::out, a); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.put('X').good() ); > + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); > + } > + } > + > + { > + // template <typename T> > + // basic_stringstream(const T&, ios_base::openmode) > + > + { > + std::stringstream strstr(cstr, mode); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.get() == cstr.s[0] ); > + VERIFY( strstr.put('X').good() ); > + } > + { > + std::stringstream strstr(cstr, std::ios::in); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.get() == cstr.s[0] ); > + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); > + } > + { > + std::stringstream strstr(cstr, std::ios::out); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.put('X').good() ); > + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); > + } > + } > + > + { > + // template <typename T> > + // explicit > + // basic_stringstream(const T&, ios_base::openmode = > ios_base::in|ios_base::out) > + > + std::stringstream strstr(cstr); > + VERIFY( strstr.str() == cstr.s ); > + VERIFY( strstr.get() == cstr.s[0] ); > + VERIFY( strstr.put('X').good() ); > + } > +} > + > +// A minimal allocator with no default constructor > +template<typename T> > + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> > + { > + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; > + NoDefaultCons() = delete; > + NoDefaultCons(int) { } > + }; > + > +template<typename Alloc, typename C = typename Alloc::value_type> > + using stringstream_with_alloc > + = std::basic_stringstream<C, std::char_traits<C>, Alloc>; > + > +void test03() > +{ > + NoDefaultCons<char> a{1}; > + { > + stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, a); > + VERIFY( std::string_view{strstr.str()} == cstr ); > + VERIFY( strstr.get() == cstr.s[0] ); > + } > + { > + stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, > std::ios::in, a); > + VERIFY( std::string_view{strstr.str()} == cstr ); > + VERIFY( strstr.get() == cstr.s[0] ); > + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); > + } > + { > + stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, > std::ios::out, a); > + VERIFY( std::string_view{strstr.str()} == cstr ); > + VERIFY( strstr.put('X').good() ); > + VERIFY( strstr.get() == std::stringbuf::traits_type::eof()); > + } > +} > + > +void test04() > +{ > + { > + std::stringstream strstr; > + strstr.str( cstr ); > + VERIFY( strstr.str() == cstr.s ); > + } > + { > + std::stringstream strstr; > + strstr.str( ccstr ); > + VERIFY( strstr.str() == ccstr.s ); > + } > +} > + > +int > +main() > +{ > + test01(); > + test02(); > + test03(); > + test04(); > +} > -- > 2.49.0 > >