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
+ // C++11 27.7.2.6 Rvalue stream extraction [istream.rvalue]
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2328. Rvalue stream extraction should use perfect forwarding
+ // 1203. More useful rvalue stream insertion
+
+ // SFINAE helper to check constraints for operator>>(Istream&&, T&&).
+ // If the constraints are satisfied, it is an alias for Istream&&.
+ template<typename _Is, typename _Tp,
+ typename = decltype(std::__rval_streamable<_Is>()
+ >> std::declval<_Tp>())>
+ using __rvalue_stream_extraction_t = _Is&&;
+
/**
* @brief Generic extractor for rvalue stream
* @param __is An input stream.
* @param __x A reference to the extraction target.
- * @return is
+ * @return __is
*
* This is just a forwarding function to allow extraction from
* rvalue streams since they won't bind to the extractor functions
* 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 __rvalue_stream_extraction_t<_Istream, _Tp>
operator>>(_Istream&& __is, _Tp&& __x)
{
- __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
{ 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;
- };
-
+ // C++11 27.7.3.9 Rvalue stream insertion [ostream.rvalue]
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 1203. More useful rvalue stream insertion
+
+ // SFINAE helper to check constraints for operator<<(Ostream&&, const T&).
+ // If Ostream is publicly and unambiguously derived from ios_base, then
+ // __rval_streamable<Ostream>() is equivalent to declval<Ostream&>().
+ // Otherwise, it results in a substitution failure. Specifically, it will
+ // fail if Ostream is an lvalue reference or the same type as ios_base.
+ // Use concepts if possible because they're cheaper to evaluate.
+#if __cpp_lib_concepts
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 {};
+ requires (!is_same_v<_Tp, ios_base>)
+ && requires (_Tp* __t, ios_base* __b) { __b = __t; }
+ _Tp&
+ __rval_streamable();
+#else
+ template<typename _Tp,
+ typename = _Require<__not_<__is_one_of<_Tp, _Tp&, ios_base>>>>
+ _Tp&
+ __rval_streamable(ios_base* = (_Tp*)nullptr);
+#endif
- template<typename _Ostream>
- using __rvalue_ostream_type =
- typename __is_convertible_to_basic_ostream<
- _Ostream>::__ostream_type;
+ // SFINAE helper to check constraints for operator<<(Ostream&&, const T&).
+ // If the constraints are satisfied, it is an alias for Ostream&&.
+ template<typename _Os, typename _Tp,
+ typename = decltype(std::__rval_streamable<_Os>()
+ << std::declval<const _Tp&>())>
+ using __rvalue_stream_insertion_t = _Os&&;
/**
* @brief Generic inserter for rvalue stream
* @param __os An input stream.
* @param __x A reference to the object being inserted.
- * @return os
+ * @return __os
*
* This is just a forwarding function to allow insertion to
* rvalue streams since they won't bind to the inserter functions
* 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 __rvalue_stream_insertion_t<_Ostream, _Tp>
operator<<(_Ostream&& __os, const _Tp& __x)
{
- __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
void
test01(std::istream& in, char* pc, signed char* sc, unsigned char* uc)
{
- in >> pc; // { dg-error "here" }
- in >> sc; // { dg-error "here" }
- in >> uc; // { dg-error "here" }
+ in >> pc; // { dg-error "no match" }
+ in >> sc; // { dg-error "no match" }
+ in >> uc; // { dg-error "no match" }
}
struct CT : std::char_traits<char> { };
test02(std::basic_istream<char, CT>& in, char* pc, signed char* sc,
unsigned char* uc)
{
- in >> pc; // { dg-error "here" }
- in >> sc; // { dg-error "here" }
- in >> uc; // { dg-error "here" }
+ in >> pc; // { dg-error "no match" }
+ in >> sc; // { dg-error "no match" }
+ in >> uc; // { dg-error "no match" }
}
// { dg-excess-errors "" }
void
test01(std::wistream& in, wchar_t* wc)
{
- in >> wc; // { dg-error "here" }
+ in >> wc; // { dg-error "no match" }
}
struct WT : std::char_traits<wchar_t> { };
void
test02(std::basic_istream<wchar_t, WT>& in, wchar_t* wc)
{
- in >> wc; // { dg-error "here" }
+ in >> wc; // { dg-error "no match" }
}
// { dg-excess-errors "" }
#include <sstream>
+template<typename Istream, typename T, typename = void>
+ struct is_extractable : std::false_type
+ { };
+
+template<typename> using void_t = void;
+
+template<typename Istream, typename T>
+ using extract_result
+ = decltype(std::declval<Istream>() >> std::declval<const T&>());
+
+template<typename Istream, typename T>
+ struct is_extractable<Istream, T, void_t<extract_result<Istream, T>>>
+ : std::true_type
+ { };
+
struct X {};
std::istream& operator>>(std::istream&, X&) = delete;
struct Z{};
-template <class T>
-auto f(T&&) -> decltype(void(std::declval<std::istream&>()
- >> std::declval<T&&>()),
- std::true_type());
-
-std::false_type f(...);
-
-template <class T>
-auto g(T&&) -> decltype(void(std::declval<std::istream&&>()
- >> std::declval<T&&>()),
- std::true_type());
-
-std::false_type g(...);
-
void test01()
{
Y y;
is >> Y();
std::istringstream() >> y;
std::istringstream() >> Y();
- static_assert(!std::__is_extractable<std::istream&, X&>::value, "");
- static_assert(!std::__is_extractable<std::istream&&, X&>::value, "");
- static_assert(!std::__is_extractable<std::istream&, X&&>::value, "");
- static_assert(!std::__is_extractable<std::istream&&, X&&>::value, "");
- static_assert(std::__is_extractable<std::istream&, Y&>::value, "");
- static_assert(std::__is_extractable<std::istream&&, Y&>::value, "");
- static_assert(std::__is_extractable<std::istream&, Y&&>::value, "");
- static_assert(std::__is_extractable<std::istream&&, Y&&>::value, "");
- static_assert(!std::__is_extractable<std::istream&, Z&>::value, "");
- static_assert(!std::__is_extractable<std::istream&&, Z&>::value, "");
- static_assert(!std::__is_extractable<std::istream&, Z&&>::value, "");
- static_assert(!std::__is_extractable<std::istream&&, Z&&>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&&>())),
- std::false_type>::value, "");
+ static_assert(!is_extractable<std::istream&, X&>::value, "");
+ static_assert(!is_extractable<std::istream&&, X&>::value, "");
+ static_assert(!is_extractable<std::istream&, X&&>::value, "");
+ static_assert(!is_extractable<std::istream&&, X&&>::value, "");
+ static_assert(is_extractable<std::istream&, Y&>::value, "");
+ static_assert(is_extractable<std::istream&&, Y&>::value, "");
+ static_assert(is_extractable<std::istream&, Y&&>::value, "");
+ static_assert(is_extractable<std::istream&&, Y&&>::value, "");
+ static_assert(!is_extractable<std::istream&, Z&>::value, "");
+ static_assert(!is_extractable<std::istream&&, Z&>::value, "");
+ static_assert(!is_extractable<std::istream&, Z&&>::value, "");
+ static_assert(!is_extractable<std::istream&&, Z&&>::value, "");
}
int main()
#include <sstream>
+template<typename Istream, typename T, typename = void>
+ struct is_extractable : std::false_type
+ { };
+
+template<typename> using void_t = void;
+
+template<typename Istream, typename T>
+ using extract_result
+ = decltype(std::declval<Istream>() >> std::declval<const T&>());
+
+template<typename Istream, typename T>
+ struct is_extractable<Istream, T, void_t<extract_result<Istream, T>>>
+ : std::true_type
+ { };
+
struct X {};
std::wistream& operator>>(std::wistream&, X&) = delete;
struct Z{};
-template <class T>
-auto f(T&&) -> decltype(void(std::declval<std::wistream&>()
- >> std::declval<T&&>()),
- std::true_type());
-
-std::false_type f(...);
-
-template <class T>
-auto g(T&&) -> decltype(void(std::declval<std::wistream&&>()
- >> std::declval<T&&>()),
- std::true_type());
-
-std::false_type g(...);
-
void test01()
{
Y y;
is >> Y();
std::wistringstream() >> y;
std::wistringstream() >> Y();
- static_assert(!std::__is_extractable<std::wistream&, X&>::value, "");
- static_assert(!std::__is_extractable<std::wistream&&, X&>::value, "");
- static_assert(!std::__is_extractable<std::wistream&, X&&>::value, "");
- static_assert(!std::__is_extractable<std::wistream&&, X&&>::value, "");
- static_assert(std::__is_extractable<std::wistream&, Y&>::value, "");
- static_assert(std::__is_extractable<std::wistream&&, Y&>::value, "");
- static_assert(std::__is_extractable<std::wistream&, Y&&>::value, "");
- static_assert(std::__is_extractable<std::wistream&&, Y&&>::value, "");
- static_assert(!std::__is_extractable<std::wistream&, Z&>::value, "");
- static_assert(!std::__is_extractable<std::wistream&&, Z&>::value, "");
- static_assert(!std::__is_extractable<std::wistream&, Z&&>::value, "");
- static_assert(!std::__is_extractable<std::wistream&&, Z&&>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&&>())),
- std::false_type>::value, "");
+ static_assert(!is_extractable<std::wistream&, X&>::value, "");
+ static_assert(!is_extractable<std::wistream&&, X&>::value, "");
+ static_assert(!is_extractable<std::wistream&, X&&>::value, "");
+ static_assert(!is_extractable<std::wistream&&, X&&>::value, "");
+ static_assert(is_extractable<std::wistream&, Y&>::value, "");
+ static_assert(is_extractable<std::wistream&&, Y&>::value, "");
+ static_assert(is_extractable<std::wistream&, Y&&>::value, "");
+ static_assert(is_extractable<std::wistream&&, Y&&>::value, "");
+ static_assert(!is_extractable<std::wistream&, Z&>::value, "");
+ static_assert(!is_extractable<std::wistream&&, Z&>::value, "");
+ static_assert(!is_extractable<std::wistream&, Z&&>::value, "");
+ static_assert(!is_extractable<std::wistream&&, Z&&>::value, "");
}
int main()
#include <sstream>
+template<typename Ostream, typename T, typename = void>
+ struct is_insertable
+ : std::false_type
+ { };
+
+template<typename> using void_t = void;
+
+template<typename Ostream, typename T>
+ using insert_result
+ = decltype(std::declval<Ostream>() << std::declval<const T&>());
+
+template<typename Ostream, typename T>
+ struct is_insertable<Ostream, T, void_t<insert_result<Ostream, T>>>
+ : std::true_type
+ { };
+
struct X {};
std::ostream& operator<<(std::ostream&, const X&) = delete;
struct Z{};
-template <class T>
-auto f(T&&) -> decltype(void(std::declval<std::ostream&>()
- << std::declval<T&&>()),
- std::true_type());
-
-std::false_type f(...);
-
-template <class T>
-auto g(T&&) -> decltype(void(std::declval<std::ostream&&>()
- << std::declval<T&&>()),
- std::true_type());
-
-std::false_type g(...);
-
void test01()
{
Y y;
os << Y();
std::ostringstream() << y;
std::ostringstream() << Y();
- static_assert(!std::__is_insertable<std::ostream&, X&>::value, "");
- static_assert(!std::__is_insertable<std::ostream&&, X&>::value, "");
- static_assert(!std::__is_insertable<std::ostream&, X&&>::value, "");
- static_assert(!std::__is_insertable<std::ostream&&, X&&>::value, "");
- static_assert(std::__is_insertable<std::ostream&, Y&>::value, "");
- static_assert(std::__is_insertable<std::ostream&&, Y&&>::value, "");
- static_assert(std::__is_insertable<std::ostream&, Y&>::value, "");
- static_assert(std::__is_insertable<std::ostream&&, Y&&>::value, "");
- static_assert(!std::__is_insertable<std::ostream&, Z&>::value, "");
- static_assert(!std::__is_insertable<std::ostream&&, Z&>::value, "");
- static_assert(!std::__is_insertable<std::ostream&, Z&&>::value, "");
- static_assert(!std::__is_insertable<std::ostream&&, Z&&>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&&>())),
- std::false_type>::value, "");
+ static_assert(!is_insertable<std::ostream&, X&>::value, "");
+ static_assert(!is_insertable<std::ostream&&, X&>::value, "");
+ static_assert(!is_insertable<std::ostream&, X&&>::value, "");
+ static_assert(!is_insertable<std::ostream&&, X&&>::value, "");
+ static_assert(is_insertable<std::ostream&, Y&>::value, "");
+ static_assert(is_insertable<std::ostream&&, Y&&>::value, "");
+ static_assert(is_insertable<std::ostream&, Y&>::value, "");
+ static_assert(is_insertable<std::ostream&&, Y&&>::value, "");
+ static_assert(!is_insertable<std::ostream&, Z&>::value, "");
+ static_assert(!is_insertable<std::ostream&&, Z&>::value, "");
+ static_assert(!is_insertable<std::ostream&, Z&&>::value, "");
+ static_assert(!is_insertable<std::ostream&&, Z&&>::value, "");
}
int main()
#include <sstream>
+template<typename Ostream, typename T, typename = void>
+ struct is_insertable
+ : std::false_type
+ { };
+
+template<typename> using void_t = void;
+
+template<typename Ostream, typename T>
+ using insert_result
+ = decltype(std::declval<Ostream>() << std::declval<const T&>());
+
+template<typename Ostream, typename T>
+ struct is_insertable<Ostream, T, void_t<insert_result<Ostream, T>>>
+ : std::true_type
+ { };
+
struct X {};
std::wostream& operator<<(std::wostream&, const X&) = delete;
struct Z{};
-template <class T>
-auto f(T&&) -> decltype(void(std::declval<std::wostream&>()
- << std::declval<T&&>()),
- std::true_type());
-
-std::false_type f(...);
-
-template <class T>
-auto g(T&&) -> decltype(void(std::declval<std::wostream&&>()
- << std::declval<T&&>()),
- std::true_type());
-
-std::false_type g(...);
-
void test01()
{
Y y;
os << Y();
std::wostringstream() << y;
std::wostringstream() << Y();
- static_assert(!std::__is_insertable<std::wostream&, X&>::value, "");
- static_assert(!std::__is_insertable<std::wostream&&, X&>::value, "");
- static_assert(!std::__is_insertable<std::wostream&, X&&>::value, "");
- static_assert(!std::__is_insertable<std::wostream&&, X&&>::value, "");
- static_assert(std::__is_insertable<std::wostream&, Y&>::value, "");
- static_assert(std::__is_insertable<std::wostream&&, Y&&>::value, "");
- static_assert(std::__is_insertable<std::wostream&, Y&>::value, "");
- static_assert(std::__is_insertable<std::wostream&&, Y&&>::value, "");
- static_assert(!std::__is_insertable<std::wostream&, Z&>::value, "");
- static_assert(!std::__is_insertable<std::wostream&&, Z&>::value, "");
- static_assert(!std::__is_insertable<std::wostream&, Z&&>::value, "");
- static_assert(!std::__is_insertable<std::wostream&&, Z&&>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(f(std::declval<Z&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<X&&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Y&&>())),
- std::true_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&>())),
- std::false_type>::value, "");
- static_assert(std::is_same<decltype(g(std::declval<Z&&>())),
- std::false_type>::value, "");
+ static_assert(!is_insertable<std::wostream&, X&>::value, "");
+ static_assert(!is_insertable<std::wostream&&, X&>::value, "");
+ static_assert(!is_insertable<std::wostream&, X&&>::value, "");
+ static_assert(!is_insertable<std::wostream&&, X&&>::value, "");
+ static_assert(is_insertable<std::wostream&, Y&>::value, "");
+ static_assert(is_insertable<std::wostream&&, Y&&>::value, "");
+ static_assert(is_insertable<std::wostream&, Y&>::value, "");
+ static_assert(is_insertable<std::wostream&&, Y&&>::value, "");
+ static_assert(!is_insertable<std::wostream&, Z&>::value, "");
+ static_assert(!is_insertable<std::wostream&&, Z&>::value, "");
+ static_assert(!is_insertable<std::wostream&, Z&&>::value, "");
+ static_assert(!is_insertable<std::wostream&&, Z&&>::value, "");
}
int main()
s >> p; // { dg-error "no match" }
}
// { dg-prune-output "no type .*enable_if" }
+// { dg-prune-output "no matching function for call to '__rval_streamable" }
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()
{
MyStream2 stream2{};
stream2 << "aaa";
stream2 >> msi;
- O{} << X{};
- I{} >> X{};
}
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;
{
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 );
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" );
+}
+
+struct A { friend void operator<<(std::ios_base&, A) { } };
+
+struct O : private std::ios_base { friend void operator<<(O&, int) { } };
+
+template<typename Ostream, typename T, typename = void>
+ struct is_insertable
+ : std::false_type
+ { };
+
+template<typename> using void_t = void;
+
+template<typename Ostream, typename T>
+ using insert_result
+ = decltype(std::declval<Ostream>() << std::declval<const T&>());
+
+template<typename Ostream, typename T>
+ struct is_insertable<Ostream, T, void_t<insert_result<Ostream, T>>>
+ : std::true_type
+ { };
+
+// LWG 1203 negative tests
+void
+test04()
+{
+ static_assert( is_insertable<std::ios_base&, A>::value,
+ "valid using the friend operator<<" );
+ static_assert( !is_insertable<std::ios_base&&, A>::value,
+ "ill-formed because ios_base is not derived from ios_base" );
+
+ static_assert( is_insertable<O&, int>::value,
+ "valid using the friend operator<<" );
+ static_assert( !is_insertable<O&&, int>::value,
+ "ill-formed because O is not publicly derived from ios_base" );
}
int
{
test01();
test02();
- return 0;
+ test03();
+ test04();
}