This implements the resolution of LWG 1203 so that the constraints for rvalue stream insertion/extraction are simpler, and the return type is the original rvalue stream type not its base class.
libstdc++-v3/ChangeLog: * include/std/istream (operator>>(Ostream&&, x&)): Simplify, as per LWG 1203. * include/std/ostream (operator<<(Ostream&&, const x&)): Likewise. * testsuite/27_io/rvalue_streams.cc: Adjust existing test. Verify LWG 1203 changes. Tested, but I won't push this until stage 1.
commit 83317035b13965ae76bc81b27ba62d8300eb9377 Author: Jonathan Wakely <jwak...@redhat.com> Date: Wed Mar 17 18:17:15 2021 libstdc++: Implement LWG 1203 for rvalue iostreams This implements the resolution of LWG 1203 so that the constraints for rvalue stream insertion/extraction are simpler, and the return type is the original rvalue stream type not its base class. libstdc++-v3/ChangeLog: * include/std/istream (operator>>(Ostream&&, x&)): Simplify, as per LWG 1203. * include/std/ostream (operator<<(Ostream&&, const x&)): Likewise. * testsuite/27_io/rvalue_streams.cc: Adjust existing test. Verify LWG 1203 changes. diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream index 24235c9b6c8..626bc797b58 100644 --- a/libstdc++-v3/include/std/istream +++ b/libstdc++-v3/include/std/istream @@ -953,57 +953,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ws(basic_istream<_CharT, _Traits>& __is); #if __cplusplus >= 201103L - template<typename _Ch, typename _Up> - basic_istream<_Ch, _Up>& - __is_convertible_to_basic_istream_test(basic_istream<_Ch, _Up>*); - - template<typename _Tp, typename = void> - struct __is_convertible_to_basic_istream_impl - { - using __istream_type = void; - }; - - template<typename _Tp> - using __do_is_convertible_to_basic_istream_impl = - decltype(__is_convertible_to_basic_istream_test - (declval<typename remove_reference<_Tp>::type*>())); - - template<typename _Tp> - struct __is_convertible_to_basic_istream_impl - <_Tp, - __void_t<__do_is_convertible_to_basic_istream_impl<_Tp>>> - { - using __istream_type = - __do_is_convertible_to_basic_istream_impl<_Tp>; - }; - - template<typename _Tp> - struct __is_convertible_to_basic_istream - : __is_convertible_to_basic_istream_impl<_Tp> - { - public: - using type = __not_<is_void< - typename __is_convertible_to_basic_istream_impl<_Tp>::__istream_type>>; - constexpr static bool value = type::value; - }; - - template<typename _Istream, typename _Tp, typename = void> - struct __is_extractable : false_type {}; - - template<typename _Istream, typename _Tp> - struct __is_extractable<_Istream, _Tp, - __void_t<decltype(declval<_Istream&>() - >> declval<_Tp>())>> - : true_type {}; - - template<typename _Istream> - using __rvalue_istream_type = - typename __is_convertible_to_basic_istream< - _Istream>::__istream_type; - // [27.7.1.6] Rvalue stream extraction // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2328. Rvalue stream extraction should use perfect forwarding + // 1203. More useful rvalue stream insertion /** * @brief Generic extractor for rvalue stream * @param __is An input stream. @@ -1015,18 +968,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * that take an lvalue reference. */ template<typename _Istream, typename _Tp> - inline - typename enable_if<__and_<__not_<is_lvalue_reference<_Istream>>, - __is_convertible_to_basic_istream<_Istream>, - __is_extractable< - __rvalue_istream_type<_Istream>, - _Tp&&>>::value, - __rvalue_istream_type<_Istream>>::type + inline auto operator>>(_Istream&& __is, _Tp&& __x) + -> __enable_if_t<is_convertible<_Istream*, ios_base*>::value, + decltype(void(__is >> std::declval<_Tp>()), + std::declval<_Istream&&>())> { - __rvalue_istream_type<_Istream> __ret_is = __is; - __ret_is >> std::forward<_Tp>(__x); - return __ret_is; + __is >> std::forward<_Tp>(__x); + return std::move(__is); } #endif // C++11 diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream index c7c4e78e8a7..f24927b80d9 100644 --- a/libstdc++-v3/include/std/ostream +++ b/libstdc++-v3/include/std/ostream @@ -704,54 +704,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __os.flush(); } #if __cplusplus >= 201103L - template<typename _Ch, typename _Up> - basic_ostream<_Ch, _Up>& - __is_convertible_to_basic_ostream_test(basic_ostream<_Ch, _Up>*); - - template<typename _Tp, typename = void> - struct __is_convertible_to_basic_ostream_impl - { - using __ostream_type = void; - }; - - template<typename _Tp> - using __do_is_convertible_to_basic_ostream_impl = - decltype(__is_convertible_to_basic_ostream_test - (declval<typename remove_reference<_Tp>::type*>())); - - template<typename _Tp> - struct __is_convertible_to_basic_ostream_impl - <_Tp, - __void_t<__do_is_convertible_to_basic_ostream_impl<_Tp>>> - { - using __ostream_type = - __do_is_convertible_to_basic_ostream_impl<_Tp>; - }; - - template<typename _Tp> - struct __is_convertible_to_basic_ostream - : __is_convertible_to_basic_ostream_impl<_Tp> - { - public: - using type = __not_<is_void< - typename __is_convertible_to_basic_ostream_impl<_Tp>::__ostream_type>>; - constexpr static bool value = type::value; - }; - - template<typename _Ostream, typename _Tp, typename = void> - struct __is_insertable : false_type {}; - - template<typename _Ostream, typename _Tp> - struct __is_insertable<_Ostream, _Tp, - __void_t<decltype(declval<_Ostream&>() - << declval<const _Tp&>())>> - : true_type {}; - - template<typename _Ostream> - using __rvalue_ostream_type = - typename __is_convertible_to_basic_ostream< - _Ostream>::__ostream_type; - + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 1203. More useful rvalue stream insertion /** * @brief Generic inserter for rvalue stream * @param __os An input stream. @@ -763,18 +717,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * that take an lvalue reference. */ template<typename _Ostream, typename _Tp> - inline - typename enable_if<__and_<__not_<is_lvalue_reference<_Ostream>>, - __is_convertible_to_basic_ostream<_Ostream>, - __is_insertable< - __rvalue_ostream_type<_Ostream>, - const _Tp&>>::value, - __rvalue_ostream_type<_Ostream>>::type + inline auto operator<<(_Ostream&& __os, const _Tp& __x) + -> __enable_if_t<is_convertible<_Ostream*, ios_base*>::value, + decltype(void(__os << __x), std::declval<_Ostream&&>())> { - __rvalue_ostream_type<_Ostream> __ret_os = __os; - __ret_os << __x; - return __ret_os; + __os << __x; + return std::move(__os); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI diff --git a/libstdc++-v3/testsuite/27_io/rvalue_streams.cc b/libstdc++-v3/testsuite/27_io/rvalue_streams.cc index def706999a3..be240698abf 100644 --- a/libstdc++-v3/testsuite/27_io/rvalue_streams.cc +++ b/libstdc++-v3/testsuite/27_io/rvalue_streams.cc @@ -25,8 +25,6 @@ void test01() { int i = 1742; - // This usage isn't supported by the current draft. - // std::string result = (std::ostringstream() << i).str(); std::ostringstream() << i; std::string result ("1742"); int i2; @@ -45,10 +43,10 @@ test02() { X x; std::istringstream is; - auto& ref1 = (std::move(is) >> x); + auto&& ref1 = (std::move(is) >> x); VERIFY( &ref1 == &is ); VERIFY( x.as_rvalue == false ); - auto& ref2 = (std::move(is) >> std::move(x)); + auto&& ref2 = (std::move(is) >> std::move(x)); VERIFY( &ref2 == &is ); VERIFY( x.as_rvalue == true ); @@ -57,6 +55,36 @@ test02() std::istringstream("x") >> &arr[0]; #endif std::istringstream("x") >> arr; + VERIFY( std::string(arr) == "x" ); +} + +// LWG 1203 More useful rvalue stream insertion +void +test03() +{ + int i = 1203; + std::string result = (std::ostringstream() << "i = " << i).str(); + VERIFY( result == "i = 1203" ); + + std::ostringstream os; + std::ostringstream&& ros = std::move(os) << result; + VERIFY( &ros == &os ); + VERIFY( ros.str() == result ); + + std::stringstream ss; + std::stringstream&& rss = std::move(ss) << result; + VERIFY( &rss == &ss ); + VERIFY( rss.str() == result ); + + std::istringstream is("first second third"); + std::istringstream&& ris = std::move(is) >> result; + VERIFY( &ris == &is ); + VERIFY( result == "first" ); + + std::stringstream ss2("fourth fifth sixth"); + std::stringstream&& rss2 = std::move(ss2) >> result; + VERIFY( &rss2 == &ss2 ); + VERIFY( result == "fourth" ); } int @@ -64,5 +92,5 @@ main() { test01(); test02(); - return 0; + test03(); }