This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofC++20 status.
Section: 31.7.6.6[ostream.rvalue], 31.7.5.6[istream.rvalue]Status:C++20Submitter: Howard HinnantOpened: 2009-09-06Last modified: 2021-02-25
Priority:2
View all otherissues in [ostream.rvalue].
View all issues withC++20 status.
Discussion:
31.7.6.6[ostream.rvalue] was created to preserve the ability to insertinto (and extract from 31.7.5.6[istream.rvalue]) rvalue streams:
template <class charT, class traits, class T> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&& os, const T& x);1Effects:
os << x2Returns:
os
This is good as it allows code that wants to (for example) open, write to, andclose anofstream all in one statement:
std::ofstream("log file") << "Some message\n";However, I think we can easily make this "rvalue stream helper" even easier touse. Consider trying to quickly create a formatted string. With the currentspec you have to write:
std::string s = static_cast<std::ostringstream&>(std::ostringstream() << "i = " << i).str();
This will store "i = 10" (for example) in the strings. Notethe need to cast the stream back toostringstream& prior to usingthe member.str(). This is necessary because the inserter has casttheostringstream down to a more genericostream during theinsertion process.
I believe we can re-specify the rvalue-inserter so that this cast is unnecessary.Thus our customer now has to only type:
std::string s = (std::ostringstream() << "i = " << i).str();
This is accomplished by having the rvalue stream inserter return an rvalue ofthe same type, instead of casting it down to the base class. This is done bymaking the stream generic, and constraining it to be an rvalue of a type derivedfromios_base.
The same argument and solution also applies to the inserter. This code has beenimplemented and tested.
[2009 Santa Cruz:]
NAD Future. No concensus for change.
[LEWG Kona 2017]
Recommend Open: Design looks right.
[2018-05-25, Billy O'Neal requests this issue be reopened and provides P/Rrebased against N4750]
Billy O'Neal requests this issue be reopened, as changing operator>>and operator<< to use perfect forwarding as described here is necessary toimplement LWG2534(i) which was accepted. Moreover, this P/R also resolvesLWG2498(i).
Previous resolution [SUPERSEDED]:
Change 31.7.5.6[istream.rvalue]:
template <classcharT, class traitsIstream, class T>basic_istream<charT, traits>&Istream&& operator>>(basic_istream<charT, traits>Istream&& is, T& x);1Effects:
is >> x2Returns:
std::move(is)3Remarks: This signature shall participate in overload resolution ifand only if
Istreamis not an lvalue reference type and is derived fromios_base.Change 31.7.6.6[ostream.rvalue]:
template <classcharT, class traitsOstream, class T>basic_ostream<charT, traits>&Ostream&& operator<<(basic_ostream<charT, traits>Ostream&& os, const T& x);1Effects:
os << x2Returns:
std::move(os)3Remarks: This signature shall participate in overload resolution ifand only if
Ostreamis not an lvalue reference type and is derived fromios_base.
[2018-12-03, Ville comments]
The implementation in libstdc++ doesn't require derivation fromios_base, it requires convertibility tobasic_istream/basic_ostream. This has been found to be important to avoid regressions with existing stream wrappers.
basic_istream/basic_ostreamspecializationthe template parameter converts to. This was done in order to try and be closer to the earlier specification's return type, which specifiedbasic_ostream<charT, traits>&andbasic_istream<charT, traits>&. So we detected convertibility to(a type convertible to) those, and returned the result of that conversion. That doesn't seem to be necessary, and probably bothers certain chaining cases. Based on recent experiments, it seemsthat this return-type dance (as opposed to just returning what the p/r suggests) is unnecessary, and doesn't trigger any regressions.[2019-01-20 Reflector prioritization]
Set Priority to 2
Previous resolution [SUPERSEDED]:
This resolution is relative to N4750.
Change 31.7.5.6[istream.rvalue] as follows:
template <classcharT, class traitsIstream, class T>basic_istream<charT, traits>&Istream&& operator>>(basic_istream<charT, traits>Istream&& is, T&& x);-1-Effects: Equivalent to:
is >> std::forward<T>(x)returnstd::move(is);-2-Remarks: This function shall not participate in overloadresolution unless the expression
is >> std::forward<T>(x)iswell-formed,Istreamis not an lvalue reference type, andIstreamis derived fromios_base.Change 31.7.6.6[ostream.rvalue]:
template <classcharT, class traitsOstream, class T>basic_ostream<charT, traits>&Ostream&& operator<<(basic_ostream<charT, traits>Ostream&& os, const T& x);-1-Effects: As if by:
os << x;-2-Returns:
std::move(os)-3-Remarks: This signature shall not participate in overload resolutionunless the expression
os << xis well-formed,Ostreamis not an lvalue reference type, andOstreamisderived fromios_base.
[2019-03-17; Daniel comments and provides updated wording]
After discussion with Ville it turns out that the "derived fromios_base" approach works fine andno breakages were found in regression tests. As result of that discussion the wording was rebased to the most recent working draft and the "overload resolution participation" wording was replaced by a correspondingConstraints: element.
[2020-02 Status to Immediate on Friday morning in Prague.]
Proposed resolution:
This wording is relative toN4810.
Change 31.7.5.6[istream.rvalue] as follows:
template <classcharT, class traitsIstream, class T>basic_istream<charT, traits>&Istream&& operator>>(basic_istream<charT, traits>Istream&& is, T&& x);-?-Constraints: The expression
-1-Effects: Equivalent to:is >> std::forward<T>(x)iswell-formed andIstreamis publicly and unambiguously derived fromios_base.is >> std::forward<T>(x);returnstd::move(is);
-2-Remarks: This function shall not participate in overload resolution unless the expressionis >> std::forward<T>(x)is well-formed.
Change 31.7.6.6[ostream.rvalue]:
template <classcharT, class traitsOstream, class T>basic_ostream<charT, traits>&Ostream&& operator<<(basic_ostream<charT, traits>Ostream&& os, const T& x);-?-Constraints: The expression
-1-Effects: As if by:os << xis well-formed andOstreamis publicly and unambiguously derived fromios_base.os << x;-2-Returns:std::move(os).-3-Remarks: This signature shall not participate in overload resolutionunless the expressionos << xis well-formed.