PR libstdc++/80675, PR libstdc++/80940
* include/std/istream: (__is_convertible_to_basic_istream_test(basic_istream<_Ch, _Up>*)): New. (__do_is_convertible_to_basic_istream_impl): Likewise. (__is_convertible_to_basic_istream_impl): Likewise. (__is_convertible_to_basic_istream): Use the new base. (__rvalue_istream_type): New. (operator>>(_Istream&&, _Tp&&)): Use the new helper alias for the SFINAE check, convert to the helper alias type before doing the actual extraction. * include/std/ostream: (__is_convertible_to_basic_ostream_test(basic_ostream<_Ch, _Up>*)): New. (__do_is_convertible_to_basic_ostream_impl): Likewise. (__is_convertible_to_basic_ostream_impl): Likewise. (__is_convertible_to_basic_ostream): Use the new base. (__rvalue_ostream_type): New. (operator<<(_Ostream&&, const _Tp&)): Use the new helper alias for the SFINAE check, convert to the helper alias type before doing the actual insertion. * testsuite/27_io/rvalue_streams-2.cc: Add new tests. From-SVN: r249468
This commit is contained in:
parent
cb8d1b01b3
commit
5e88d2d08d
4 changed files with 159 additions and 29 deletions
|
@ -1,3 +1,27 @@
|
|||
2017-06-21 Ville Voutilainen <ville.voutilainen@gmail.com>
|
||||
|
||||
PR libstdc++/80675
|
||||
PR libstdc++/80940
|
||||
* include/std/istream:
|
||||
(__is_convertible_to_basic_istream_test(basic_istream<_Ch, _Up>*)): New.
|
||||
(__do_is_convertible_to_basic_istream_impl): Likewise.
|
||||
(__is_convertible_to_basic_istream_impl): Likewise.
|
||||
(__is_convertible_to_basic_istream): Use the new base.
|
||||
(__rvalue_istream_type): New.
|
||||
(operator>>(_Istream&&, _Tp&&)): Use the new helper alias
|
||||
for the SFINAE check, convert to the helper alias type before
|
||||
doing the actual extraction.
|
||||
* include/std/ostream:
|
||||
(__is_convertible_to_basic_ostream_test(basic_ostream<_Ch, _Up>*)): New.
|
||||
(__do_is_convertible_to_basic_ostream_impl): Likewise.
|
||||
(__is_convertible_to_basic_ostream_impl): Likewise.
|
||||
(__is_convertible_to_basic_ostream): Use the new base.
|
||||
(__rvalue_ostream_type): New.
|
||||
(operator<<(_Ostream&&, const _Tp&)): Use the new helper alias
|
||||
for the SFINAE check, convert to the helper alias type before
|
||||
doing the actual insertion.
|
||||
* testsuite/27_io/rvalue_streams-2.cc: Add new tests.
|
||||
|
||||
2017-06-21 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
|
||||
|
||||
* config/abi/post/aarch64-linux-gnu/baseline_symbols.txt: Update.
|
||||
|
|
|
@ -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>
|
||||
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>
|
||||
{
|
||||
template<typename _Ch, typename _Up>
|
||||
static basic_istream<_Ch, _Up>& __check(basic_istream<_Ch, _Up>*);
|
||||
|
||||
static void __check(...);
|
||||
public:
|
||||
using istream_type =
|
||||
decltype(__check(declval<typename remove_reference<_Tp>::type*>()));
|
||||
using type = __not_<is_same<istream_type, void>>;
|
||||
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 {};
|
||||
|
@ -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_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{};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue