@@ -908,20 +908,39 @@ _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>
- struct __is_convertible_to_basic_istream
+ 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>>>
{
- template<typename _Ch, typename _Up>
- static basic_istream<_Ch, _Up>& __check(basic_istream<_Ch, _Up>*);
+ using __istream_type =
+ __do_is_convertible_to_basic_istream_impl<_Tp>;
+ };
- static void __check(...);
+ template<typename _Tp>
+ struct __is_convertible_to_basic_istream
+ : __is_convertible_to_basic_istream_impl<_Tp>
+ {
public:
- using istream_type =
- decltype(__check(declval<typename remove_reference<_Tp>::type*>()));
- using type = __not_<is_same<istream_type, void>>;
+ using type = __not_<is_same<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 {};
@@ -932,6 +951,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> 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
@@ -949,13 +973,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline
typename enable_if<__and_<__not_<is_lvalue_reference<_Istream>>,
__is_convertible_to_basic_istream<_Istream>,
- __is_extractable<_Istream&, _Tp&&>>::value,
- typename __is_convertible_to_basic_istream<
- _Istream>::istream_type>::type
+ __is_extractable<
+ __rvalue_istream_type<_Istream>,
+ _Tp&&>>::value,
+ __rvalue_istream_type<_Istream>>::type
operator>>(_Istream&& __is, _Tp&& __x)
{
- __is >> std::forward<_Tp>(__x);
- return __is;
+ __rvalue_istream_type<_Istream> __ret_is = __is;
+ __ret_is >> std::forward<_Tp>(__x);
+ return __ret_is;
}
#endif // C++11
@@ -613,19 +613,39 @@ _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
- {
- template<typename _Ch, typename _Up>
- static basic_ostream<_Ch, _Up>& __check(basic_ostream<_Ch, _Up>*);
-
- static void __check(...);
- public:
- using ostream_type =
- decltype(__check(declval<typename remove_reference<_Tp>::type*>()));
- using type = __not_<is_same<ostream_type, void>>;
- constexpr static bool value = type::value;
- };
+ : __is_convertible_to_basic_ostream_impl<_Tp>
+ {
+ public:
+ using type = __not_<is_same<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 {};
@@ -636,6 +656,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
<< declval<const _Tp&>())>>
: true_type {};
+ template<typename _Ostream>
+ using __rvalue_ostream_type =
+ typename __is_convertible_to_basic_ostream<
+ _Ostream>::__ostream_type;
+
/**
* @brief Generic inserter for rvalue stream
* @param __os An input stream.
@@ -650,13 +675,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline
typename enable_if<__and_<__not_<is_lvalue_reference<_Ostream>>,
__is_convertible_to_basic_ostream<_Ostream>,
- __is_insertable<_Ostream&, const _Tp&>>::value,
- typename __is_convertible_to_basic_ostream<
- _Ostream>::ostream_type>::type
+ __is_insertable<
+ __rvalue_ostream_type<_Ostream>,
+ const _Tp&>>::value,
+ __rvalue_ostream_type<_Ostream>>::type
operator<<(_Ostream&& __os, const _Tp& __x)
{
- __os << __x;
- return __os;
+ __rvalue_ostream_type<_Ostream> __ret_os = __os;
+ __ret_os << __x;
+ return __ret_os;
}
#endif // C++11
@@ -24,11 +24,64 @@ struct A {};
void operator<<(std::ostream&, const A&) { }
void operator>>(std::istream&, A&) { }
+class MyStream : private std::ostream, private std::istream
+{
+public:
+ MyStream& operator <<(const char*)
+ {
+ return *this;
+ }
+ MyStream& operator >>(int&)
+ {
+ return *this;
+ }
+};
+
+class MyStream2
+{
+public:
+ MyStream2& operator <<(const char*)
+ {
+ return *this;
+ }
+ MyStream2& operator >>(int&)
+ {
+ return *this;
+ }
+private:
+ operator std::ostream&();
+ operator std::istream&();
+};
+
+struct X { };
+
+std::ostream& operator<<(std::ostream& os, const X&) { return os; }
+std::istream& operator>>(std::istream& is, X&&) { return is; }
+
+struct O : std::ostream { };
+
+void operator<<(O&, X) = delete;
+
+struct I : std::istream { };
+
+void operator>>(I&, X) = delete;
+
// PR libstdc++/65543
+// PR libstdc++/80675
+// PR libstdc++/80940
int main()
{
A a;
std::ostringstream() << a;
std::istringstream() >> a;
+ MyStream stream{};
+ stream << "aaa";
+ int msi;
+ stream >> msi;
+ MyStream2 stream2{};
+ stream2 << "aaa";
+ stream2 >> msi;
+ O{} << X{};
+ I{} >> X{};
}