Index: include/istream =================================================================== --- include/istream +++ include/istream @@ -1378,13 +1378,19 @@ #ifndef _LIBCPP_CXX03_LANG -template +template inline _LIBCPP_INLINE_VISIBILITY -basic_istream<_CharT, _Traits>& -operator>>(basic_istream<_CharT, _Traits>&& __is, _Tp&& __x) +typename enable_if +< + (__has_in_stream_op<_Stream&, _Tp& >::value || + __has_in_stream_op<_Stream&, _Tp&&>::value) && + is_base_of::value, + _Stream&& +>::type +operator>>(_Stream&& __is, _Tp&& __x) { __is >> _VSTD::forward<_Tp>(__x); - return __is; + return _VSTD::move(__is); } #endif // _LIBCPP_CXX03_LANG Index: include/ostream =================================================================== --- include/ostream +++ include/ostream @@ -1027,7 +1027,8 @@ inline _LIBCPP_INLINE_VISIBILITY typename enable_if < - !is_lvalue_reference<_Stream>::value && + (__has_out_stream_op<_Stream&, _Tp&>::value || + __has_out_stream_op<_Stream&&, _Tp&>::value) && is_base_of::value, _Stream&& >::type Index: include/type_traits =================================================================== --- include/type_traits +++ include/type_traits @@ -831,6 +831,7 @@ _LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool is_rvalue_reference_v = is_rvalue_reference<_Tp>::value; #endif + // is_union #if __has_feature(is_union) || defined(_LIBCPP_COMPILER_GCC) @@ -4909,6 +4910,35 @@ } #endif +#ifndef _LIBCPP_CXX03_LANG +// __has_stream_op + +template +struct __has_out_stream_op +{ + template + static auto test(int) -> decltype(declval<_T1>() << declval<_U1>()); + + template + static auto test(...) -> false_type; + + static constexpr bool value = !is_same(0))>::value; +}; + +template +struct __has_in_stream_op +{ + template + static auto test(int) -> decltype(declval<_T1>() >> declval<_U1>()); + + template + static auto test(...) -> false_type; + + static constexpr bool value = !is_same(0))>::value; +}; + +#endif // _LIBCPP_CXX03_LANG + _LIBCPP_END_NAMESPACE_STD #if _LIBCPP_STD_VER > 14 Index: test/std/input.output/iostream.format/input.streams/istream.rvalue/ios_base_operator_overload_resolution.fail.cpp =================================================================== --- /dev/null +++ test/std/input.output/iostream.format/input.streams/istream.rvalue/ios_base_operator_overload_resolution.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template > +// class basic_istream; + +// template +// basic_ostream& +// operator>>(basic_istream&& os, const T& x); + +// LWG: 2534 and 1203 + +#include + +#include "test_macros.h" + +struct A {}; + +int main(int, char**) +{ + std::istringstream is; + std::move(is) >> A{}; // expected-error-re {{invalid operands to binary expression {{.*}}}} + + return 0; +} Index: test/std/input.output/iostream.format/input.streams/istream.rvalue/perfect_forwarding.pass.cpp =================================================================== --- /dev/null +++ test/std/input.output/iostream.format/input.streams/istream.rvalue/perfect_forwarding.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template +// basic_istream& +// operator>>(basic_istream&& is, T&& x); + +#include +#include +#include + +#include "test_macros.h" + +struct A{}; +struct B{}; + +bool rval = false; +bool lval = false; + +void operator>>(std::istream&, A&&){ rval = true; } +void operator>>(std::istream&, B& ){ lval = true; } + +int main(int, char**) +{ + { + std::istringstream ss; + std::move(ss) >> A{}; + assert(rval); + } + { + std::istringstream ss; + B b; + std::move(ss) >> b; + assert(lval); + } + + return 0; +} Index: test/std/input.output/iostream.format/output.streams/ostream.rvalue/ios_base_operator_overload_resolution.fail.cpp =================================================================== --- /dev/null +++ test/std/input.output/iostream.format/output.streams/ostream.rvalue/ios_base_operator_overload_resolution.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template > +// class basic_ostream; + +// template +// basic_ostream& +// operator<<(basic_ostream&& os, const T& x); + +// LWG: 2534 and 1203 + +#include + +#include "test_macros.h" + +struct A {}; + +int main(int, char**) +{ + std::stringstream os; + std::move(os) << A{}; // expected-error-re {{invalid operands to binary expression {{.*}}}} + + return 0; +}