Skip to content

Commit c90dee1

Browse files
committed
[libc++] Re-apply fdc41e1 (LWG1203) without breaking the C++11 build
fdc41e1 was reverted in e46c1de because it broke the C++11 build. We shouldn't be using enable_if_t in C++11, instead we must use enable_if<...>::type.
1 parent dfa9065 commit c90dee1

File tree

7 files changed

+118
-45
lines changed

7 files changed

+118
-45
lines changed

libcxx/include/istream

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ template <class charT, class traits>
150150
basic_istream<charT,traits>&
151151
ws(basic_istream<charT,traits>& is);
152152
153-
template <class charT, class traits, class T>
154-
basic_istream<charT, traits>&
155-
operator>>(basic_istream<charT, traits>&& is, T& x);
153+
// rvalue stream extraction
154+
template <class Stream, class T>
155+
Stream&& operator>>(Stream&& is, T&& x);
156156
157157
} // std
158158
@@ -1378,13 +1378,23 @@ ws(basic_istream<_CharT, _Traits>& __is)
13781378

13791379
#ifndef _LIBCPP_CXX03_LANG
13801380

1381-
template <class _CharT, class _Traits, class _Tp>
1382-
inline _LIBCPP_INLINE_VISIBILITY
1383-
basic_istream<_CharT, _Traits>&
1384-
operator>>(basic_istream<_CharT, _Traits>&& __is, _Tp&& __x)
1381+
template <class _Stream, class _Tp, class = void>
1382+
struct __is_istreamable : false_type { };
1383+
1384+
template <class _Stream, class _Tp>
1385+
struct __is_istreamable<_Stream, _Tp, decltype(
1386+
_VSTD::declval<_Stream>() >> _VSTD::declval<_Tp>(), void()
1387+
)> : true_type { };
1388+
1389+
template <class _Stream, class _Tp, class = typename enable_if<
1390+
_And<is_base_of<ios_base, _Stream>,
1391+
__is_istreamable<_Stream&, _Tp&&>>::value
1392+
>::type>
1393+
_LIBCPP_INLINE_VISIBILITY
1394+
_Stream&& operator>>(_Stream&& __is, _Tp&& __x)
13851395
{
13861396
__is >> _VSTD::forward<_Tp>(__x);
1387-
return __is;
1397+
return _VSTD::move(__is);
13881398
}
13891399

13901400
#endif // _LIBCPP_CXX03_LANG

libcxx/include/ostream

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,8 @@ template <class charT, class traits>
126126
basic_ostream<charT,traits>& flush(basic_ostream<charT,traits>& os);
127127
128128
// rvalue stream insertion
129-
template <class charT, class traits, class T>
130-
basic_ostream<charT, traits>&
131-
operator<<(basic_ostream<charT, traits>&& os, const T& x);
129+
template <class Stream, class T>
130+
Stream&& operator<<(Stream&& os, const T& x);
132131
133132
} // std
134133
@@ -1028,15 +1027,20 @@ flush(basic_ostream<_CharT, _Traits>& __os)
10281027

10291028
#ifndef _LIBCPP_CXX03_LANG
10301029

1030+
template <class _Stream, class _Tp, class = void>
1031+
struct __is_ostreamable : false_type { };
1032+
10311033
template <class _Stream, class _Tp>
1032-
inline _LIBCPP_INLINE_VISIBILITY
1033-
typename enable_if
1034-
<
1035-
!is_lvalue_reference<_Stream>::value &&
1036-
is_base_of<ios_base, _Stream>::value,
1037-
_Stream&&
1038-
>::type
1039-
operator<<(_Stream&& __os, const _Tp& __x)
1034+
struct __is_ostreamable<_Stream, _Tp, decltype(
1035+
_VSTD::declval<_Stream>() << _VSTD::declval<_Tp>(), void()
1036+
)> : true_type { };
1037+
1038+
template <class _Stream, class _Tp, class = typename enable_if<
1039+
_And<is_base_of<ios_base, _Stream>,
1040+
__is_ostreamable<_Stream&, const _Tp&>>::value
1041+
>::type>
1042+
_LIBCPP_INLINE_VISIBILITY
1043+
_Stream&& operator<<(_Stream&& __os, const _Tp& __x)
10401044
{
10411045
__os << __x;
10421046
return _VSTD::move(__os);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03
10+
11+
// Make sure the rvalue overload of operator>> isn't part of the overload set
12+
// when the type is not input streamable from a lvalue stream.
13+
14+
#include <istream>
15+
#include <utility>
16+
17+
struct Foo { };
18+
19+
using X = decltype(std::declval<std::istream>() >> std::declval<Foo&>()); // expected-error {{invalid operands to binary expression}}
20+
using Y = decltype(std::declval<std::istream>() >> std::declval<Foo>()); // expected-error {{invalid operands to binary expression}}

libcxx/test/std/input.output/iostream.format/input.streams/istream.rvalue/rvalue.pass.cpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@
1010

1111
// <istream>
1212

13-
// template <class charT, class traits, class T>
14-
// basic_istream<charT, traits>&
15-
// operator>>(basic_istream<charT, traits>&& is, T&& x);
13+
// template <class Stream, class T>
14+
// Stream&& operator>>(Stream&& is, T&& x);
1615

1716
#include <istream>
1817
#include <sstream>
@@ -44,32 +43,44 @@ struct testbuf
4443
CharT* egptr() const {return base::egptr();}
4544
};
4645

46+
struct Int {
47+
int value;
48+
template <class CharT>
49+
friend void operator>>(std::basic_istream<CharT>& is, Int& self) {
50+
is >> self.value;
51+
}
52+
};
4753

48-
struct A{};
54+
struct A { };
4955
bool called = false;
50-
void operator>>(std::istream&, A&&){ called = true; }
56+
void operator>>(std::istream&, A&&) { called = true; }
5157

5258
int main(int, char**)
5359
{
5460
{
5561
testbuf<char> sb(" 123");
56-
int i = 0;
57-
std::istream(&sb) >> i;
58-
assert(i == 123);
62+
Int i = {0};
63+
std::istream is(&sb);
64+
std::istream&& result = (std::move(is) >> i);
65+
assert(&result == &is);
66+
assert(i.value == 123);
5967
}
6068
{
6169
testbuf<wchar_t> sb(L" 123");
62-
int i = 0;
63-
std::wistream(&sb) >> i;
64-
assert(i == 123);
70+
Int i = {0};
71+
std::wistream is(&sb);
72+
std::wistream&& result = (std::move(is) >> i);
73+
assert(&result == &is);
74+
assert(i.value == 123);
6575
}
66-
{ // test perfect forwarding
76+
{
77+
// test perfect forwarding
6778
assert(called == false);
6879
std::istringstream ss;
69-
auto&& out = (std::move(ss) >> A{});
70-
assert(&out == &ss);
80+
std::istringstream&& result = (std::move(ss) >> A{});
81+
assert(&result == &ss);
7182
assert(called);
7283
}
7384

74-
return 0;
85+
return 0;
7586
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03
10+
11+
// Make sure the rvalue overload of operator<< isn't part of the overload set
12+
// when the type is not output streamable into a lvalue stream.
13+
14+
#include <ostream>
15+
#include <utility>
16+
17+
struct Foo { };
18+
19+
using X = decltype(std::declval<std::ostream>() << std::declval<Foo const&>()); // expected-error {{invalid operands to binary expression}}
Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,8 @@
1010

1111
// <ostream>
1212

13-
// template <class charT, class traits = char_traits<charT> >
14-
// class basic_ostream;
15-
16-
// template <class charT, class traits, class T>
17-
// basic_ostream<charT, traits>&
18-
// operator<<(basic_ostream<charT, traits>&& os, const T& x);
13+
// template <class Stream, class T>
14+
// Stream&& operator<<(Stream&& os, const T& x);
1915

2016
#include <ostream>
2117
#include <cassert>
@@ -55,19 +51,32 @@ class testbuf
5551
}
5652
};
5753

54+
struct Int {
55+
int value;
56+
template <class CharT>
57+
friend void operator<<(std::basic_ostream<CharT>& os, Int const& self) {
58+
os << self.value;
59+
}
60+
};
5861

5962
int main(int, char**)
6063
{
6164
{
6265
testbuf<char> sb;
63-
std::ostream(&sb) << "testing...";
64-
assert(sb.str() == "testing...");
66+
std::ostream os(&sb);
67+
Int const i = {123};
68+
std::ostream&& result = (std::move(os) << i);
69+
assert(&result == &os);
70+
assert(sb.str() == "123");
6571
}
6672
{
6773
testbuf<wchar_t> sb;
68-
std::wostream(&sb) << L"123";
74+
std::wostream os(&sb);
75+
Int const i = {123};
76+
std::wostream&& result = (std::move(os) << i);
77+
assert(&result == &os);
6978
assert(sb.str() == L"123");
7079
}
7180

72-
return 0;
81+
return 0;
7382
}

libcxx/www/cxx2a_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ <h3>Library Working group Issues Status</h3>
468468
<tr><td><a href="https://wg21.link/LWG3149">3149</a></td><td><tt>DefaultConstructible</tt> should require default initialization</td><td>Belfast</td><td></td></tr>
469469

470470
<tr><td></td><td></td><td></td><td></td></tr> -->
471-
<tr><td><a href="https://wg21.link/LWG1203">1203</a></td><td>More useful rvalue stream insertion</td><td>Prague</td><td></td></tr>
471+
<tr><td><a href="https://wg21.link/LWG1203">1203</a></td><td>More useful rvalue stream insertion</td><td>Prague</td><td>12.0</td></tr>
472472
<tr><td><a href="https://wg21.link/LWG2859">2859</a></td><td>Definition of <em>reachable</em> in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object</td><td>Prague</td><td></td></tr>
473473
<tr><td><a href="https://wg21.link/LWG3018">3018</a></td><td><tt>shared_ptr</tt> of function type</td><td>Prague</td><td></td></tr>
474474
<tr><td><a href="https://wg21.link/LWG3050">3050</a></td><td>Conversion specification problem in <tt>chrono::duration</tt> constructor</td><td>Prague</td><td></td></tr>

0 commit comments

Comments
 (0)