Topic: Streaming ranges


Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Sun, 6 Jul 2014 12:15:50 -0700 (PDT)
Raw View
------=_Part_94_33350384.1404674150033
Content-Type: text/plain; charset=UTF-8

There is a proposal (N4007) for "delimited iterators". Basically, it adds a
new "ostream_joiner" that you can use instead of the traditional
ostream_iterator, like this:

vector<int> v = {1, 4, 6};
cout << "(";
copy(v.begin(), v.end(), make_ostream_joiner(cout, ", "));
cout << ")";
// Prints "(1, 4, 6)"

While that's all fine and good, using stream iterators to read/write
sequences has always been difficult.

   - They require using std::copy(), for what isn't really a copy operation
   (I don't think anyone refers to "operator<<(ostream&, T)" or
   "operator>>(istream&, T&)" as "copy operators"), which makes it unclear
   what the code is actually doing.
   - They require a bunch of extra libraries. Beyond what you need for the
   stream and the sequence, you also need <iterator> and <algorithm>, and
   <algorithm> in particular is pretty heavyweight.
   - The input version is one of the most infamous examples of the most
   vexing parse.
   - It's just verbose and clumsy. Most programmers I talked to said they'd
   rather hand roll a range for loop. (In fact, even in standard proposal
   documents, I see people doing this.)

Stream iterators are an excellent tool for more complex tasks (for example,
doing a transform that takes elements from two input ranges and streams the
result, or reading only elements that match some criteria from an input
stream into a container and discarding the rest), but for the most basic
job of simply dumping the contents of a sequence to output or reading input
into a sequence, they're rather clumsy. Streaming a whole range seems to me
to be such a frequent and fundamental operation that it really should have
a dedicated algorithm or construct for its use - something so simple that
even a beginner can be comfortable using it.

I considered a dedicated algorithm like "to_ostream(cout, v.begin(),
v.end());" (or, with ranges, "to_ostream(cout, v);"), but perhaps a better
solution might be a manipulator-like interface, like this:

cout << stream_range(make_array(1, 2, 3)); // Prints "123"
cout << '(' << stream_range(v, ", ") << ')'; // Prints "(1, 4, 6)"

where "stream_range()" is defined in one of the IOStreams headers (maybe
<iomanip>, or maybe both <istream> and <ostream> with the extraction
operators for the proxy objects in the former and the insertion operators
in the latter).

The proxy object created by stream_range() would copy the arguments if they
were rvalues, but only keep references to lvalue arguments (because ranges
are probably going to be pretty heavy objects). Lifetime management should
not be a problem, so long as the return value of stream_range() does not
outlive the range it references (assuming it doesn't actually own the
range, as it would if the range had been passed as an rvalue).

You could also have a version that takes iterators (though, if anything
like N3350's std::range<Iterator> is approved, it won't really be
necessary):

cout << '(' << stream_iterator_range(v.begin(), v.end(), ", ") << ')';

The same manipulator form could be used for input:

auto a = std::array<double, 5>;
cin >> stream_range(a); // Reads 5 doubles from cin into a
cin >> stream_iterator_range(a.begin(), a.end()); // Same, with iterators

The overload with a delimiter obviously shouldn't work for istreams:

auto a = std::array<double, 5>;
cin >> stream_range(a, ", "); // Compiler error

(But maybe rvalue ranges can be okay, so that you can use "cin >>
stream_range(std::array<double, 5>{});" to read and then discard 5 doubles
from cin.)

For the common case where you want to stream values into a container that
grows while accepting them, you could have constructs like this:

auto v = std::vector<int>{};
v.resize(5);

// Extract an unknown number of items, stopping when bool(cin) is false,
// putting the extracted items...
cin >> stream_range_back_insert(v);                // ... at the end.
cin >> stream_range_front_insert(v);               // ... at the front.
cin >> stream_range_insert(v, next(v.begin(), 3)); // ... before the third
element.

// Extract up to 10 items, stopping early if bool(cin) is false,
// putting the extracted items...
cin >> stream_range_back_insert(v, 10);                // ... at the end.
cin >> stream_range_front_insert(v, 10);               // ... at the front.
cin >> stream_range_insert(v, next(v.begin(), 3), 10); // ... before the
third element.

Of course, attempting to use any of these with an ostream should result in
a compile error.

At the moment, I'm not sure how to implement these using a generic range
interface, because the most recent proposal for ranges I've seen doesn't
support inserting. When that gets clarified, this can be implemented.

Has anyone ever proposed anything like this? Would anyone object to a
proposal like this? Are there any concerns or problems I might have
overlooked?

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_94_33350384.1404674150033
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">There is a proposal (N4007) for "delimited iterators". Bas=
ically, it adds a new "ostream_joiner" that you can use instead of the trad=
itional ostream_iterator, like this:<br><br><div class=3D"prettyprint" styl=
e=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187)=
; border-style: solid; border-width: 1px; word-wrap: break-word;"><code cla=
ss=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000=
;" class=3D"styled-by-prettify">vector</span><span style=3D"color: #080;" c=
lass=3D"styled-by-prettify">&lt;int&gt;</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> v </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">{</span><span style=3D"color: #066;" class=3D"styled-by-prettify">1=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">4</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"=
styled-by-prettify">6</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br>cout </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 </span><span style=3D"color: #080;" class=3D"styled-by-prettify">"("</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>copy</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">.</span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">begin</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">(),</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> v</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>.</span><span style=3D"color: #008;" class=3D"styled-by-prettify">end</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> make_ostream_joiner</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">cout</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;"=
 class=3D"styled-by-prettify">", "</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">));</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>cout </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-prett=
ify">")"</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span>=
<span style=3D"color: #800;" class=3D"styled-by-prettify">// Prints "(1, 4,=
 6)"</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></=
span></div></code></div><br>While that's all fine and good, using stream it=
erators to read/write sequences has always been difficult.<br><ul><li>They =
require using std::copy(), for what isn't really a copy operation (I don't =
think anyone refers to "operator&lt;&lt;(ostream&amp;, T)" or "operator&gt;=
&gt;(istream&amp;, T&amp;)" as "copy operators"), which makes it unclear wh=
at the code is actually doing.</li><li>They require a bunch of extra librar=
ies. Beyond what you need for the stream and the sequence, you also need &l=
t;iterator&gt; and &lt;algorithm&gt;, and &lt;algorithm&gt; in particular i=
s pretty heavyweight.</li><li>The input version is one of the most infamous=
 examples of the most vexing parse.</li><li>It's just verbose and clumsy. M=
ost programmers I talked to said they'd rather hand roll a range for loop. =
(In fact, even in standard proposal documents, I see people doing this.)</l=
i></ul>Stream iterators are an excellent tool for more complex tasks (for e=
xample, doing a transform that takes elements from two input ranges and str=
eams the result, or reading only elements that match some criteria from an =
input stream into a container and discarding the rest), but for the most ba=
sic job of simply dumping the contents of a sequence to output or reading i=
nput into a sequence, they're rather clumsy. Streaming a whole range seems =
to me to be such a frequent and fundamental operation that it really should=
 have a dedicated algorithm or construct for its use - something so simple =
that even a beginner can be comfortable using it.<br><br>I considered a ded=
icated algorithm like "to_ostream(cout, v.begin(), v.end());" (or, with ran=
ges, "to_ostream(cout, v);"), but perhaps a better solution might be a mani=
pulator-like interface, like this:<br><br><div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
 border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;=
" class=3D"styled-by-prettify">cout </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> stream_range</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">make_array</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">(</span><span style=3D"color: #066;" class=3D"styled-by-p=
rettify">1</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #066;" class=3D"styled-by-prettify">2</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;"=
 class=3D"styled-by-prettify">3</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">));</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prett=
ify">// Prints "123"</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br>cout </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">'(=
'</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> stream_range</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">", "</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #080;" class=3D"styled-by-prettify">')'</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #800;" class=3D"styled-by-prettify">// Prints "(1, 4, 6)"</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code><=
/div><br>where "stream_range()" is defined in one of the IOStreams headers =
(maybe &lt;iomanip&gt;, or maybe both &lt;istream&gt; and &lt;ostream&gt; w=
ith the extraction operators for the proxy objects in the former and the in=
sertion operators in the latter).<br><br>The proxy object created by stream=
_range() would copy the arguments if they were rvalues, but only keep refer=
ences to lvalue arguments (because ranges are probably going to be pretty h=
eavy objects). Lifetime management should not be a problem, so long as the =
return value of stream_range() does not outlive the range it references (as=
suming it doesn't actually own the range, as it would if the range had been=
 passed as an rvalue).<br><br>You could also have a version that takes iter=
ators (though, if anything like N3350's std::range&lt;Iterator&gt; is appro=
ved, it won't really be necessary):<br><br><div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
 border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;=
" class=3D"styled-by-prettify">cout </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=3D"style=
d-by-prettify">'('</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> st=
ream_iterator_range</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> v</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #008;"=
 class=3D"styled-by-prettify">end</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(),</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-pr=
ettify">", "</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span styl=
e=3D"color: #080;" class=3D"styled-by-prettify">')'</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span></div></code></div><br>The same =
manipulator form could be used for input:<br><br><div class=3D"prettyprint"=
 style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187,=
 187); border-style: solid; border-width: 1px; word-wrap: break-word;"><cod=
e class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color:=
 #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> a </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">array</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&l=
t;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">double</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">5</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&gt;;</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> stream_range</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">a</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">//=
 Reads 5 doubles from cin into a</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> stream_iterator_range</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">a</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">.</span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">begin</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(),</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> a<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">end</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">());</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #80=
0;" class=3D"styled-by-prettify">// Same, with iterators</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></di=
v><br>The overload with a delimiter obviously shouldn't work for istreams:<=
br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, =
250); border-color: rgb(187, 187, 187); border-style: solid; border-width: =
1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">auto<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> a </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> std</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify">array</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">double</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">5</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;;<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>cin </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> stream_range</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">a</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" =
class=3D"styled-by-prettify">", "</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pre=
ttify">// Compiler error</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"><br></span></div></code></div><br>(But maybe rvalue ranges ca=
n be okay, so that you can use "cin &gt;&gt; stream_range(std::array&lt;dou=
ble, 5&gt;{});" to read and then discard 5 doubles from cin.)<br><br>For th=
e common case where you want to stream values into a container that grows w=
hile accepting them, you could have constructs like this:<br><br><div class=
=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: b=
reak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span=
 style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> v </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">vector</span><span style=3D"color: #080;" class=3D"style=
d-by-prettify">&lt;int&gt;</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">{};</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>v</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">resiz=
e</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><=
span style=3D"color: #066;" class=3D"styled-by-prettify">5</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"color=
: #800;" class=3D"styled-by-prettify">// Extract an unknown number of items=
, stopping when bool(cin) is false,</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" class=3D"s=
tyled-by-prettify">// putting the extracted items...</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> stream_range_back_insert</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp=
; &nbsp;</span><span style=3D"color: #800;" class=3D"styled-by-prettify">//=
 ... at the end.</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br>cin </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> stream_range_front_insert</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style=3D"color: #800=
;" class=3D"styled-by-prettify">// ... at the front.</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> stream_range_insert</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">next</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">v</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #06=
6;" class=3D"styled-by-prettify">3</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">));</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pr=
ettify">// ... before the third element.</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #800;" c=
lass=3D"styled-by-prettify">// Extract up to 10 items, stopping early if bo=
ol(cin) is false,</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br></span><span style=3D"color: #800;" class=3D"styled-by-prettify"=
>// putting the extracted items...</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> stream_range_back_insert</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">10</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> &nbsp; &nbsp=
; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style=3D"color: #80=
0;" class=3D"styled-by-prettify">// ... at the end.</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> stream_range_front_insert</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"sty=
led-by-prettify">10</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style=3D"co=
lor: #800;" class=3D"styled-by-prettify">// ... at the front.</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>cin </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> stream_range_insert</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">next</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">begin</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #066;" class=3D"styled-by-prettify">3</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">),</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styl=
ed-by-prettify">10</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// ... be=
fore the third element.</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br></span></div></code></div><br>Of course, attempting to use=
 any of these with an ostream should result in a compile error.<br><br>At t=
he moment, I'm not sure how to implement these using a generic range interf=
ace, because the most recent proposal for ranges I've seen doesn't support =
inserting. When that gets clarified, this can be implemented.<br><br>Has an=
yone ever proposed anything like this? Would anyone object to a proposal li=
ke this? Are there any concerns or problems I might have overlooked?<br></d=
iv>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_94_33350384.1404674150033--

.


Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Fri, 18 Jul 2014 12:08:24 -0700 (PDT)
Raw View
------=_Part_298_1467781562.1405710504713
Content-Type: text/plain; charset=UTF-8

I have created a reference implementation of stream_range and
stream_iterator_range in C++11
<https://github.com/DarkerStar/cpp-range-streaming>.
(https://github.com/DarkerStar/cpp-range-streaming)

The reference implementation currently has input and output versions of
stream_range (including the output version that takes a delimiter), and
input and output versions of stream_iterator_range (again, with optional
delimiter).

I am currently thinking of dropping stream_iterator_range, because "
stream_iterator_range(b, e[, d])" is just "stream_range(make_range(b, e)[,
d])" (assuming a make_range() function like what is proposed in N3350,
which seems likely).

I haven't done implementations of stream_range_back_insert,
stream_range_front_insert, or stream_range_insert, because I'm not sure how
to implement them. There are two issues I'm mulling over:

   1. How to determine the value_type for the range without requiring the
   iterators library. Currently, range streaming has no dependencies except
   utility and iosfwd. It would be nice to keep it that way.
   2. How to create the object that will be "read into" (because istream
   extraction requires the object being read into to already exist). I could
   insist on the value type having a default constructor, but that seems
   unnecessarily restrictive. I could have an optional parameter that defaults
   to a default constructed object, but that would mean that I can't have the
   overloads that take a number (those would require another function).

If anyone has any suggestions or comments, let me know.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_298_1467781562.1405710504713
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I have created a <a href=3D"https://github.com/DarkerStar/=
cpp-range-streaming">reference implementation of stream_range and stream_it=
erator_range in C++11</a>. (https://github.com/DarkerStar/cpp-range-streami=
ng)<br><br>The reference implementation currently has input and output vers=
ions of stream_range (including the output version that takes a delimiter),=
 and input and output versions of stream_iterator_range (again, with option=
al delimiter).<br><br>I am currently thinking of dropping stream_iterator_r=
ange, because <span style=3D"color: #000;" class=3D"styled-by-prettify"><co=
de>"</code>stream_iterator_range</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">b</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> e<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">[,</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> d</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">])</span><code class=3D"pre=
ttyprint"></code>" is just "stream_range(make_range(b, e)[, d])" (assuming =
a make_range() function like what is proposed in N3350, which seems likely)=
..<br><br>I haven't done implementations of stream_range_back_insert, stream=
_range_front_insert, or stream_range_insert, because I'm not sure how to im=
plement them. There are two issues I'm mulling over:<br><ol><li>How to dete=
rmine the value_type for the range without requiring the iterators library.=
 Currently, range streaming has no dependencies except utility and iosfwd. =
It would be nice to keep it that way.<br></li><li>How to create the object =
that will be "read into" (because istream extraction requires the object be=
ing read into to already exist). I could insist on the value type having a =
default constructor, but that seems unnecessarily restrictive. I could have=
 an optional parameter that defaults to a default constructed object, but t=
hat would mean that I can't have the overloads that take a number (those wo=
uld require another function).<br></li></ol>If anyone has any suggestions o=
r comments, let me know.<br> </div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_298_1467781562.1405710504713--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sun, 20 Jul 2014 11:58:45 -0700 (PDT)
Raw View
------=_Part_172_941386822.1405882725643
Content-Type: text/plain; charset=UTF-8

I like this idea. Simple common things should be simple to do!

Note that the input usage is almost the same as the spilt() function that
has been proposed before although split works from a string(_view) and
push_backs the receiving container as needed. join could be a suitable name
for the output function. The input case is considerably more complex and
those issues can be handled by the split() proposal, advanced cases with
user defined helper classes.

I'm sceptical to the idea of a input function receiving into a range, as
the typical use case is to not know the length in advance, and it is very
logical to a programmer to just state "push back the incoming things into
this container, please".  It is unfortunate that there is no common method
name to do a push_back() for sequential and insert() for sorted container
so that this type of function can easily be implemented. back_inserter
solves this but raises the level of complexity at the point of usage which
is unfortunate. Traits or enable_if stuff can of course hide this but it
gets harder to extend to new containers than if stl containers had a common
"append" or similar.

I think these two suggestions should be synchronized so that we get one
functionaliy which can do both input and output between a string or stream
and a  container or range, and which includes the splitting options offered
by the split proposal.

Call sites should look something like:

cout << join(v, ", ");        // join is essentially the stream_range
object.
string s = join(v, ", ");     // But with a conversion operator to string.
(1)


split(s, v, ", ");               // Split as proposed. s is actually a
string_view which allows most types of "stringy" objects to be used as the
source.
split(cin, v, ",");              // Split working from an input stream.


(1) this does not reduce performance notably compared to sending s as an
out parameter to join thanks to rvalue string ctor.

It could be worth investigating if join() should be elaborated with some
more options like split(), for instance to handle a limited line length or
n-items per row printout, as well as maybe fixed width comlumns with space
fill and things like that.

It may be unfortunate that join and split limp a bit when it comes to how
the stream/string parameter is handled but I fail to see how a string can
easily be used for this parameter otherwise. Overloading operator >> for
string as the left argument would be possible but then this will be
expected work for all right arguments. This, on the other hand has
advantages (error handling is not one of them!).

An alternative is to let split() without the string parameter return a
helper object with an overloaded >> from istream, which does the work:

split(s, v, ",");      // This split function does the work and returns void
cin >> split(v, ",");  // This split returns a helper object which holds a
reference to v etc. operator>> does the splitting.



One problem with this option is that the word split feels odd here. fill()
or something seems more descriptive, but is not good for the first
overload. To me sending the stream in to split seems as the best choice.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_172_941386822.1405882725643
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>I like this idea. Simple common things should be simp=
le to do!</div><div><br></div><div>Note that the input usage is almost the =
same as the spilt() function that has been proposed before although split w=
orks from a string(_view) and push_backs the receiving container as needed.=
 join could be a suitable name for the output function. The input case is c=
onsiderably more complex and those issues can be handled by the split() pro=
posal, advanced cases with user defined helper classes.</div><div><br></div=
><div>I'm sceptical to the idea of a input function receiving into a range,=
 as the typical use case is to not know the length in advance, and it is ve=
ry logical to a programmer to just state "push back the incoming things int=
o this container, please". &nbsp;It is unfortunate that there is no common =
method name to do a push_back() for sequential and insert() for sorted cont=
ainer so that this type of function can easily be implemented. back_inserte=
r solves this but raises the level of complexity at the point of usage whic=
h is unfortunate. Traits or enable_if stuff can of course hide this but it =
gets harder to extend to new containers than if stl containers had a common=
 "append" or similar.</div><div><br></div><div>I think these two suggestion=
s should be synchronized so that we get one functionaliy which can do both =
input and output between a string or stream and a &nbsp;container or range,=
 and which includes the splitting options offered by the split proposal.</d=
iv><div><br></div><div>Call sites should look something like:</div><div><br=
></div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, =
187); word-wrap: break-word; background-color: rgb(250, 250, 250);"><code c=
lass=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">cout </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> join</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">v</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </=
span><span style=3D"color: #080;" class=3D"styled-by-prettify">", "</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> &nbsp; &nbsp; &nbsp; &nbs=
p;</span><span style=3D"color: #800;" class=3D"styled-by-prettify">// join =
is essentially the stream_range object.</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">string</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> s </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> join</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">v</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #080;" class=3D"styled-by-prettify">", "</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> &nbsp; &nbsp; </span><span style=3D"color: #800;=
" class=3D"styled-by-prettify">// But with a conversion operator to string.=
 (1)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><b=
r><br>split</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">s</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> v</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">", "</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span st=
yle=3D"color: #800;" class=3D"styled-by-prettify">// Split as proposed. s i=
s actually a string_view which allows most types of "stringy" objects to be=
 used as the source.</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br>split</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
cin</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> v</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #08=
0;" class=3D"styled-by-prettify">","</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><=
span style=3D"color: #800;" class=3D"styled-by-prettify">// Split working f=
rom an input stream.</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br><br></span></div></code></div><div><br>(1) this does not redu=
ce performance notably compared to sending s as an out parameter to join th=
anks to rvalue string ctor.</div><div><br></div><div>It could be worth inve=
stigating if join() should be elaborated with some more options like split(=
), for instance to handle a limited line length or n-items per row printout=
, as well as maybe fixed width comlumns with space fill and things like tha=
t.</div><div><br></div><div>It may be unfortunate that join and split limp =
a bit when it comes to how the stream/string parameter is handled but I fai=
l to see how a string can easily be used for this parameter otherwise. Over=
loading operator &gt;&gt; for string as the left argument would be possible=
 but then this will be expected work for all right arguments. This, on the =
other hand has advantages (error handling is not one of them!).</div><div><=
br></div><div>An alternative is to let split() without the string parameter=
 return a helper object with an overloaded &gt;&gt; from istream, which doe=
s the work:</div><div><br></div><div class=3D"prettyprint" style=3D"border:=
 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb=
(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"=
><span style=3D"color: #000;" class=3D"styled-by-prettify">split</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">s</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> v</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettif=
y">","</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> &nbsp; &nbs=
p; &nbsp;</span><span style=3D"color: #800;" class=3D"styled-by-prettify">/=
/ This split function does the work and returns void</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> split</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">",=
"</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> &nbsp;</span><sp=
an style=3D"color: #800;" class=3D"styled-by-prettify">// This split return=
s a helper object which holds a reference to v etc. operator&gt;&gt; does t=
he splitting.</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br><br>&nbsp;</span></div></code></div><div><br></div><div>One problem =
with this option is that the word split feels odd here. fill() or something=
 seems more descriptive, but is not good for the first overload. To me send=
ing the stream in to split seems as the best choice.</div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_172_941386822.1405882725643--

.


Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Sun, 20 Jul 2014 16:44:38 -0700 (PDT)
Raw View
------=_Part_179_281622497.1405899878268
Content-Type: text/plain; charset=UTF-8

On Sunday, 20 July 2014 14:58:45 UTC-4, Bengt Gustafsson wrote:
>
> I think these two suggestions should be synchronized so that we get one
> functionaliy which can do both input and output between a string or stream
> and a  container or range, and which includes the splitting options offered
> by the split proposal.
>

When I first read your suggestions, I thought that would be the perfect
solution - not only would it eliminate the need for another standard
library name (I've been using "stream_range", which is clunky), it would
create a single interface to do what seem to be similar jobs.

But the more I thought about it, the more I realized this would be a
mistake. While the operations of join() and stream_range() seem
superficially similar from a really distant perspective, there are enough
subtle differences in the practical application and the ways these
functions will probably be used to make it impossible to use the same
function for both jobs. Also, it would essentially just be reinventing the
same problem that inspired me to make the suggestion in the first place -
it shouldn't be necessary to include the algorithms library to do basic
I/O, and streaming a range should be basic I/O (put yourself in the shoes
of a beginner who has just written a simple C++ program that includes the
vector header and the iostream header, then does nothing in main but create
a vector v and try to write it with "std::cout << std::stream_range(v);"...
only to discover the program won't compile because you're missing the
"algorithm" header, leaving you scratching your head because you didn't
really use any algorithms: you just tried to print a vector).

But there are more dangerous problems, too. For example, if we merged this
functionality into join(), then join() would have to return a proxy object
that references the source range rather than a string. This may seem fine,
especially if the proxy object has an implicit conversion to string, but:

class team
{
public:
  void add_player(string s) { players_.push_back(move(s)); }
  void drop_player(string const& s) { players_.erase(find(players_.begin(),
players_.end(), s)); }

  auto current_roster() const
  {
    // If join() returned a string - as currently spec'ed - no problems in
this
    // entire program. But if join() returns an adaptable proxy object with
an
    // implicit string conversion that lazy-evaluates....
    return join(players_, ", ");
  }

private:
  vector<string> players_;
};

auto t = team{};
t.add_player("Bruiser");
t.add_player("T-bone");

// No problems yet...
auto s1 = std::string{};
s1 = t.current_roster(); // proxy object implicit string conv gives
"Bruiser, T-bone"
cout << t.current_roster(); // proxy object prints "Bruiser, T-bone"


// Uh oh!
auto team_before = t.current_roster(); // proxy object references internal
vector
                                       // (contains: "Bruiser", "T-bone")

t.drop_player("Bruiser");
t.add_player("Stabby");

// Proxy object team_before now references vector with "T-bone", "Stabby"!

auto team_after = t.current_roster(); // proxy object references internal
vector
                                      // (contains: "T-bone", "Stabby")

cout << "Team before trade: " << team_before << '\n';
cout << "Team after trade:  " << team_after << '\n';
// Output is:
// Team before trade: T-bone, Stabby
// Team after trade:  T-bone, Stabby

Try explaining that error to a beginner.

What's happening here is that the proxy object that either streams or
"strings" has to hold a reference to the original range. It can't copy it
(that would be expensive), and it can't know until it is used whether it
will be used to make a string or for streaming. Unless you explicitly cast
the result of join() to a string (or assign it to a string), you're getting
the proxy object, which, with auto and return type deduction, means you may
not be aware that you're trucking around a proxy object that probably holds
a reference to the original range. If the original range goes out of scope
before the proxy object (and the example above can be easily modified to
demonstrate that), bang. Even if it doesn't, you can get surprising
results, as shown above.

Between this and the problem of which header to put join() in, I just can't
see a way to resolve the two different types of functionality down to a
single function. Consider the following two statements:

cout << "{ " << join(v, ", ") << " }";
cout << "{ " << stream_range(v, ", ") << " }";

They both look the same, and they both give identical results... but they
do it in very, very different ways under the hood (in this case, join()
would probably be quite inefficient compared to stream_range() - in
non-streaming cases, the opposite would be true). It is not inconceivable
that a programmer might want to insist on the behaviour of the first
statement or the second - taking away the option of choosing what they want
(or at least making it more difficult to do so) seems counterproductive.
And more importantly, they are both very different types of tasks. The
former is to join the elements of the range into an object that you can
hold on to and pass around (a string, in this case), while the latter is to
coordinate output in a stream expression and is not intended to create a
new, independent object. Strings and streams are just too different for
there to be a single function to handle both. The apparent similarities are
just superficial.

Which is too bad - I would have liked to use "join" (rather than
"stream_range").


> I'm sceptical to the idea of a input function receiving into a range, as
> the typical use case is to not know the length in advance, and it is very
> logical to a programmer to just state "push back the incoming things into
> this container, please".
>

My intention is to ultimately have a family of functions for input - the
only one I've done so far is the one that overwrites a range with input
values.

I don't think it's that rare to want to read a known number of values into
a range, and there is currently no way to do it without manually writing a
loop. You can't use copy_n() with an istream iterator, because it doesn't
check for EOF (or any problems, really) - if the input stream goes bad
halfway through, you end up with your container half-full of garbage
(likely the last properly read value repeated). I don't think it's that
rare to have an object of fixed size and to expect to read exactly that
many values (for example, reading a 3d transformation matrix - it's always
going to be 16 elements), or to have input that gives the number of items
in a list before the list itself (that's a rather common file structure,
really).

Also, consider buffering. One of the ideas I'm toying with is to have the
proxy object have a count() function, giving the number of items
successfully written/read (and maybe a reset() function to reset it to 0).
So suppose you have a huge dataset - you can read in 100 values at a time
and work with them like this:

auto buffer = std::array<double, 100>{};

while (in)
{
  auto p = std::stream_range(buffer);
  in >> p; // That's it for input! This will attempt to read 100 doubles,
and
           // it will stop early and gracefully if it can't.

  if (p.count())
  {
    auto working_range = make_range(begin(buffer), next(begin(buffer), p.
count()));

    // Now do your calculations with whatever was read in.
  }

  // Or instead of the if block above, you can do:
  // auto working_range = make_range(begin(buffer), next(begin(buffer),
p.count()));
  // if (!empty(working_range)) { ... }
}

While reading into an expanding range should be an option, I don't think it
should be the only option. Expanding is expensive and not fail-safe, so in
cases where you can know the number of items to read before reading, you
should always prefer to at least reserve() the space, if not straight-up
create the receiving range already properly sized then read into it.

Once I work out the wrinkles, I am going to add 3 more functions, which I
am currently calling stream_range_back_insert(),
stream_range_front_insert(), and stream_range_insert(), but which could
just as well be called back_insert(), front_insert(), and insert(), because
this is the only possible context where they can take 1, 1, and 2 arguments
respectively. They would handle the case where you don't know the number of
elements beforehand:

std::cin >> std::stream_range(v); // Replaces all elements of v with input.

std::cin >> std::back_insert(v); // Adds elements using v.push_back(x).
std::cin >> std::front_insert(v); // Adds elements using v.push_front(x).
std::cin >> std::insert(v, i); // Adds elements using v.insert(i, x).

// In all cases above, input stops when bool(std::cin) is false.
// If you want to know how many items were actually successfully read (only
// relevant in the first case, really), you should do:
// auto p = std::stream_range(v); // or whichever function you wish to use
// std::cin >> p;
// And the number of successfully read items is in p.count().

At the moment I'm not concerned with the names - that can be dealt with
later. (For example, maybe "overwrite" could be used for the first case
above, and "output" or "write_all" could be used for the ostream version.)
I'm more concerned with making this as flexible as possible, while keeping
it easy to use. One of the things I'm most concerned with is adding means
to detect if and - more importantly - when I/O failed. That's something
that no current method (using stream iterators or algorithms like copy)
does, and unfortunately, split() doesn't seem equipped to do it either
(along with its other issues, like being in the algorithms library).


> It could be worth investigating if join() should be elaborated with some
> more options like split(), for instance to handle a limited line length or
> n-items per row printout, as well as maybe fixed width comlumns with space
> fill and things like that.
>

That seems like going way beyond the mandate of a simple range streaming
facility. Those things might be useful (though I'm not particularly sure
that standardizing a pretty-printing text output library is worth the
effort in an age of graphical UIs), but the sheer number of permutations of
reasonable options is just too much to even begin to consider for a basic
function.

If this is worth investigating (I'm not convinced), it should be
investigated as an entirely separate library, because it isn't really
related to ranges or streaming ranges.


> An alternative is to let split() without the string parameter return a
> helper object with an overloaded >> from istream, which does the work:
>

As far as I know, split() is defined as taking a source string(view) and a
delimiter - it doesn't take the output range, it returns a proxy object
made up of string_views into the original string. Have there been changes
since N3593? Because if not, with that interface, there's really no way to
handle both "regular" splitting, and "splitting" from an input stream.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_179_281622497.1405899878268
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Sunday, 20 July 2014 14:58:45 UTC-4, Bengt Gustafsson  =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>I =
think these two suggestions should be=20
synchronized so that we get one functionaliy which can do both input and
 output between a string or stream and a &nbsp;container or range, and whic=
h=20
includes the splitting options offered by the split proposal.</div></div></=
blockquote><div><br>When I first read your suggestions, I thought that woul=
d be the perfect solution - not only would it eliminate the need for anothe=
r standard library name (I've been using "stream_range", which is clunky), =
it would create a single interface to do what seem to be similar jobs.<br><=
br>But the more I thought about it, the more I realized this would be a mis=
take. While the operations of join() and stream_range() seem superficially =
similar from a really distant perspective, there are enough subtle differen=
ces in the practical application and the ways these functions will probably=
 be used to make it impossible to use the same function for both jobs. Also=
, it would essentially just be reinventing the same problem that inspired m=
e to make the suggestion in the first place - it shouldn't be necessary to =
include the algorithms library to do basic I/O, and streaming a range shoul=
d be basic I/O (put yourself in the shoes of a beginner who has just writte=
n a simple C++ program that includes the vector header and the iostream hea=
der, then does nothing in main but create a vector v and try to write it wi=
th "std::cout &lt;&lt; std::stream_range(v);"... only to discover the progr=
am won't compile because you're missing the "algorithm" header, leaving you=
 scratching your head because you didn't really use any algorithms: you jus=
t tried to print a vector).<br><br>But there are more dangerous problems, t=
oo. For example, if we merged this functionality into join(), then join() w=
ould have to return a proxy object that references the source range rather =
than a string. This may seem fine, especially if the proxy object has an im=
plicit conversion to string, but:<br><br><div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
 border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;=
" class=3D"styled-by-prettify">class</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> team<br></span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">public</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">:</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
>&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-prettify">vo=
id</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> add_pla=
yer</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">string</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> s</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> players_</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">push_back</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
move</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">s</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">));</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">void</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> drop_player</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">string</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">const</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&am=
p;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> s</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> players_</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">erase</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">find</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">playe=
rs_</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> players_</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">end</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">(),</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> s</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">));</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp=
; <br>&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> cu=
rrent_roster</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">()</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">const</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; </span><sp=
an style=3D"color: #800;" class=3D"styled-by-prettify">// If join() returne=
d a string - as currently spec'ed - no problems in this</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; </span><sp=
an style=3D"color: #800;" class=3D"styled-by-prettify">// entire program. B=
ut if join() returns an adaptable proxy object with an</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; </span><span =
style=3D"color: #800;" class=3D"styled-by-prettify">// implicit string conv=
ersion that lazy-evaluates....</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br>&nbsp; &nbsp; </span><span style=3D"color: #008;" c=
lass=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> join</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">players_</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #080;" class=3D"styled-by-prettify">", "</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br>&nbsp; <br></span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">private</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>&nbsp; vector</span><span style=
=3D"color: #080;" class=3D"styled-by-prettify">&lt;string&gt;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> players_</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> t </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> team</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
{};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>t</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">add_player</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #080;" class=3D"styled-by-prettify">"Bruiser"</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br>t</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">.</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">add_player</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">(</span><span style=3D"color: #080;" class=3D"styl=
ed-by-prettify">"T-bone"</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br><br></span><span style=3D"color: #800;" class=3D"styled-by-pretti=
fy">// No problems yet...</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> s1 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">string</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{};</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br>s1 </span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> t</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">current_roster</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">();</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettif=
y">// proxy object implicit string conv gives "Bruiser, T-bone"</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"><br>cout </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> t</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">current_roster</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">();</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D=
"styled-by-prettify">// proxy object prints "Bruiser, T-bone"</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br><br><br></span><span=
 style=3D"color: #800;" class=3D"styled-by-prettify">// Uh oh!</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> team_before </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> t</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">current_roster</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pr=
ettify">// proxy object references internal vector</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nb=
sp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &=
nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style=3D"color: #800;" class=
=3D"styled-by-prettify">// (contains: "Bruiser", "T-bone")</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br><br>t</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">drop_player</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #080;"=
 class=3D"styled-by-prettify">"Bruiser"</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br>t</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">add_player</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">(</span><span style=3D"color: #080;" class=3D"styled-by-prettify">"S=
tabby"</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">// Proxy objec=
t team_before now references vector with "T-bone", "Stabby"!</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> team_after </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> t</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">current_roster</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pr=
ettify">// proxy object references internal vector</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nb=
sp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &=
nbsp; &nbsp; &nbsp; &nbsp; </span><span style=3D"color: #800;" class=3D"sty=
led-by-prettify">// (contains: "T-bone", "Stabby")</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br><br>cout </span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080=
;" class=3D"styled-by-prettify">"Team before trade: "</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> team_before </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">'\n'</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>cout </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">"Te=
am after trade: &nbsp;"</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> team_after </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">'\n'</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #800;" class=3D"styled-by-prettify">// Output is:</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D=
"color: #800;" class=3D"styled-by-prettify">// Team before trade: T-bone, S=
tabby</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
/span><span style=3D"color: #800;" class=3D"styled-by-prettify">// Team aft=
er trade: &nbsp;T-bone, Stabby</span></div></code></div><br>Try explaining =
that error to a beginner.<br><br>What's happening here is that the proxy ob=
ject that either streams or "strings" has to hold a reference to the origin=
al range. It can't copy it (that would be expensive), and it can't know unt=
il it is used whether it will be used to make a string or for streaming. Un=
less you explicitly cast the result of join() to a string (or assign it to =
a string), you're getting the proxy object, which, with auto and return typ=
e deduction, means you may not be aware that you're trucking around a proxy=
 object that probably holds a reference to the original range. If the origi=
nal range goes out of scope before the proxy object (and the example above =
can be easily modified to demonstrate that), bang. Even if it doesn't, you =
can get surprising results, as shown above.<br><br>Between this and the pro=
blem of which header to put join() in, I just can't see a way to resolve th=
e two different types of functionality down to a single function. Consider =
the following two statements:<br><br><div class=3D"prettyprint" style=3D"ba=
ckground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); borde=
r-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"p=
rettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">cout </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-p=
rettify">"{ "</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&l=
t;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> join</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" cla=
ss=3D"styled-by-prettify">", "</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 </span><span style=3D"color: #080;" class=3D"styled-by-prettify">" }"</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>cout </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #080;" class=3D"styled-by-prettify">"{ "</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> stream_range</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">v</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 </span><span style=3D"color: #080;" class=3D"styled-by-prettify">", "</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;=
" class=3D"styled-by-prettify">" }"</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">;</span></div></code></div><br>They both look the =
same, and they both give identical results... but they do it in very, very =
different ways under the hood (in this case, join() would probably be quite=
 inefficient compared to stream_range() - in non-streaming cases, the oppos=
ite would be true). It is not inconceivable that a programmer might want to=
 insist on the behaviour of the first statement or the second - taking away=
 the option of choosing what they want (or at least making it more difficul=
t to do so) seems counterproductive. And more importantly, they are both ve=
ry different types of tasks. The former is to join the elements of the rang=
e into an object that you can hold on to and pass around (a string, in this=
 case), while the latter is to coordinate output in a stream expression and=
 is not intended to create a new, independent object. Strings and streams a=
re just too different for there to be a single function to handle both. The=
 apparent similarities are just superficial.<br><br>Which is too bad - I wo=
uld have liked to use "join" (rather than "stream_range").<br>&nbsp;</div><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">I'm sceptical =
to the idea of a input function receiving into a range, as the typical use =
case is to not know the length in advance, and it is very logical to a prog=
rammer to just state "push back the incoming things into this container, pl=
ease".</div></blockquote><div><br>My intention is to ultimately have a fami=
ly of functions for input - the only one I've done so far is the one that o=
verwrites a range with input values.<br><br>I don't think it's that rare to=
 want to read a known number of values into a range, and there is currently=
 no way to do it without manually writing a loop. You can't use copy_n() wi=
th an istream iterator, because it doesn't check for EOF (or any problems, =
really) - if the input stream goes bad halfway through, you end up with you=
r container half-full of garbage (likely the last properly read value repea=
ted). I don't think it's that rare to have an object of fixed size and to e=
xpect to read exactly that many values (for example, reading a 3d transform=
ation matrix - it's always going to be 16 elements), or to have input that =
gives the number of items in a list before the list itself (that's a rather=
 common file structure, really).<br><br>Also, consider buffering. One of th=
e ideas I'm toying with is to have the proxy object have a count() function=
, giving the number of items successfully written/read (and maybe a reset()=
 function to reset it to 0). So suppose you have a huge dataset - you can r=
ead in 100 values at a time and work with them like this:<br><br><div class=
=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: b=
reak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span=
 style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> buffer </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">array</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">double</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">100</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;{};</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">while</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">in</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br>&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> p <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">stream_range</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">buffer</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">in</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> p</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #800;" class=3D"styled-by-prettify">// That's it for i=
nput! This will attempt to read 100 doubles, and</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp=
; &nbsp;</span><span style=3D"color: #800;" class=3D"styled-by-prettify">//=
 it will stop early and gracefully if it can't.</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"><br>&nbsp; <br>&nbsp; </span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">if</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">p</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">count</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>())</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&n=
bsp; </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; &nb=
sp; </span><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> working_ran=
ge </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> make_range</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
 style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">buffer</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">),</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">next</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">begin</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">buffer</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">),</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> p</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">count</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">()));</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>&nbsp; &nbsp; <br>&nbsp; &nbsp; </span><span s=
tyle=3D"color: #800;" class=3D"styled-by-prettify">// Now do your calculati=
ons with whatever was read in.</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br>&nbsp; <br>&nbsp; </span><span style=3D"color: #800;" class=
=3D"styled-by-prettify">// Or instead of the if block above, you can do:</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </=
span><span style=3D"color: #800;" class=3D"styled-by-prettify">// auto work=
ing_range =3D make_range(begin(buffer), next(begin(buffer), p.count()));</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </=
span><span style=3D"color: #800;" class=3D"styled-by-prettify">// if (!empt=
y(working_range)) { ... }</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">}</span></div></code></div><br>While reading into an expanding ran=
ge should be an option, I don't think it should be the only option. Expandi=
ng is expensive and not fail-safe, so in cases where you can know the numbe=
r of items to read before reading, you should always prefer to at least res=
erve() the space, if not straight-up create the receiving range already pro=
perly sized then read into it.<br><br>Once I work out the wrinkles, I am go=
ing to add 3 more functions, which I am currently calling stream_range_back=
_insert(), stream_range_front_insert(), and stream_range_insert(), but whic=
h could just as well be called back_insert(), front_insert(), and insert(),=
 because this is the only possible context where they can take 1, 1, and 2 =
arguments respectively. They would handle the case where you don't know the=
 number of elements beforehand:<br><br><div class=3D"prettyprint" style=3D"=
background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bor=
der-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D=
"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">cin </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">stream_ran=
ge</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800=
;" class=3D"styled-by-prettify">// Replaces all elements of v with input.</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br>std<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">cin </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">back_insert</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">=
// Adds elements using v.push_back(x).</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">cin </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">front=
_insert</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify">v</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #800;" class=3D"styled-by-prettify">// Adds elements using v.push_front(x=
).</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>std<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">cin </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">insert</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> i</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #800;" class=3D"styled-by-prettify">// Adds elements using=
 v.insert(i, x).</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br><br></span><span style=3D"color: #800;" class=3D"styled-by-pretti=
fy">// In all cases above, input stops when bool(std::cin) is false.</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span =
style=3D"color: #800;" class=3D"styled-by-prettify">// If you want to know =
how many items were actually successfully read (only</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: =
#800;" class=3D"styled-by-prettify">// relevant in the first case, really),=
 you should do:</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br></span><span style=3D"color: #800;" class=3D"styled-by-prettify">/=
/ auto p =3D std::stream_range(v); // or whichever function you wish to use=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span=
><span style=3D"color: #800;" class=3D"styled-by-prettify">// std::cin &gt;=
&gt; p;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
></span><span style=3D"color: #800;" class=3D"styled-by-prettify">// And th=
e number of successfully read items is in p.count().</span></div></code></d=
iv><br>At the moment I'm not concerned with the names - that can be dealt w=
ith later. (For example, maybe "overwrite" could be used for the first case=
 above, and "output" or "write_all" could be used for the ostream version.)=
 I'm more concerned with making this as flexible as possible, while keeping=
 it easy to use. One of the things I'm most concerned with is adding means =
to detect if and - more importantly - when I/O failed. That's something tha=
t no current method (using stream iterators or algorithms like copy) does, =
and unfortunately, split() doesn't seem equipped to do it either (along wit=
h its other issues, like being in the algorithms library).<br>&nbsp;</div><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"> <div>It could=
 be worth investigating if join() should be elaborated with some more optio=
ns like split(), for instance to handle a limited line length or n-items pe=
r row printout, as well as maybe fixed width comlumns with space fill and t=
hings like that.</div></div></blockquote><div><br>That seems like going way=
 beyond the mandate of a simple range streaming facility. Those things migh=
t be useful (though I'm not particularly sure that standardizing a pretty-p=
rinting text output library is worth the effort in an age of graphical UIs)=
, but the sheer number of permutations of reasonable options is just too mu=
ch to even begin to consider for a basic function.<br><br>If this is worth =
investigating (I'm not convinced), it should be investigated as an entirely=
 separate library, because it isn't really related to ranges or streaming r=
anges.<br>&nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr"><div>An alternative is to let split() without the string parameter=
 return a helper object with an overloaded &gt;&gt; from istream, which doe=
s the work:</div></div></blockquote><div><br>As far as I know, split() is d=
efined as taking a source string(view) and a delimiter - it doesn't take th=
e output range, it returns a proxy object made up of string_views into the =
original string. Have there been changes since N3593? Because if not, with =
that interface, there's really no way to handle both "regular" splitting, a=
nd "splitting" from an input stream.</div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_179_281622497.1405899878268--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Tue, 22 Jul 2014 02:01:32 -0700 (PDT)
Raw View
------=_Part_206_2030496647.1406019692182
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

A proposal to define an "operator auto" so that a class with "lazy"=20
semantics can be instructed to convert to a certain type (in this case=20
string) when "converted to auto", such as in your function current_roster.=
=20
I think is a typical usecase for that functionality... Unfortunately I=20
forgot the exact syntax proposed but it was something like: auto operator=
=20
<type>() {} or <type> operator auto() {}

I think you got things messed up in your comparison of join() and=20
stream_range() in the ostream shift example: The sole reason for having a=
=20
proxy object and getting the (now solved) problem with the hidden proxy=20
object was that this proxy object can be the rhs of a << operator without=
=20
the interveaning conversion to string! Now you claim the performance=20
penalty of join is still there. Maybe this was under the assumption that a=
=20
proxy object would be unacceptable and thus join just returning string...=
=20
For the programmer join seems to return string and the proxy object is only=
=20
a QoI possibility (although the committe will probably see issues with=20
leaving the existance of the proxy object up to the implementation).

I didn't chcek N3593 again, I was just assuming it took the output sequence=
=20
as an object to be able to use different types of containers. But all=20
right, as the element type is string_view that would rather be a template=
=20
template parameter to indicate what type of container you want back. As >>=
=20
operators return the istream split can of course not return the container=
=20
of parts too. But a split taking an istream as parameter would still be=20
possible, although it would have to return a vector<string> instead of=20
vector<string_view>. Also I missed the rather obvious difference that split=
=20
can't convert the parts to something else than strings... What I was after=
=20
was the rather neat (albeit intricate) ways you can specify the delimiting=
=20
in that proposal (and also counts). I still think that synergy should be=20
used. I don't see the problem with the algorithm header as any other header=
=20
using it would of course include it. That is, unless you are worried about=
=20
compile times.

But you may be right in that the istream shifting into a container is=20
important enough to warrant a separate functionality. I don't like the=20
separate function names though, and offer that the basic function could=20
take a template template parameter which defaults to back_inserter. A=20
"overwriting" inserter would be used to handle your range case (where you=
=20
use stream_range). The naming is a later issue but insert is a bit odd.=20
elements_of() reads better in context, I think:

cin >> elements_of(v);                                               //=20
Uses back_inserter as expected as default
cin >> elements_of<front_inserter>(v);                      // Puts the=20
elements first (in reverse order???)
cin >> elements_of<inserter>(v, next(v, 10));            // Puts the=20
elements at index 10 (not in reverse order I assume)
cin >> elements_of<replacer>(v, next(v, 10), next(v, 20)); // Replaces up=
=20
to 10 elements of v. I think y proper overloading and maybe enable_if we=20
can get rid of the redundant 'v' parameter here.

The idea of giving the proxy object returned by elements_of a name and=20
allow it to return the count is still valid as you indicated.

What remains is how to convey the insert position for the "center insert"=
=20
case and a possibility to send in a subrange of a container to the=20
"replacer" version. I propose to solve this using an additional parameter=
=20
pack forwarded to the inserter:

template<template<typename> inserter, typename C, typename... Ps>=20
_unspecified_ element_of(C& container, Ps&& ps) { return=20
_unspecified_<inserter<typename C::value_type>>(inserter<typename=20
C::value_type>(C, ps...)); }



Den m=C3=A5ndagen den 21:e juli 2014 kl. 01:44:38 UTC+2 skrev Mark A. Gibbs=
:
>
> On Sunday, 20 July 2014 14:58:45 UTC-4, Bengt Gustafsson wrote:
>>
>> I think these two suggestions should be synchronized so that we get one=
=20
>> functionaliy which can do both input and output between a string or stre=
am=20
>> and a  container or range, and which includes the splitting options offe=
red=20
>> by the split proposal.
>>
>
> When I first read your suggestions, I thought that would be the perfect=
=20
> solution - not only would it eliminate the need for another standard=20
> library name (I've been using "stream_range", which is clunky), it would=
=20
> create a single interface to do what seem to be similar jobs.
>
> But the more I thought about it, the more I realized this would be a=20
> mistake. While the operations of join() and stream_range() seem=20
> superficially similar from a really distant perspective, there are enough=
=20
> subtle differences in the practical application and the ways these=20
> functions will probably be used to make it impossible to use the same=20
> function for both jobs. Also, it would essentially just be reinventing th=
e=20
> same problem that inspired me to make the suggestion in the first place -=
=20
> it shouldn't be necessary to include the algorithms library to do basic=
=20
> I/O, and streaming a range should be basic I/O (put yourself in the shoes=
=20
> of a beginner who has just written a simple C++ program that includes the=
=20
> vector header and the iostream header, then does nothing in main but crea=
te=20
> a vector v and try to write it with "std::cout << std::stream_range(v);".=
...=20
> only to discover the program won't compile because you're missing the=20
> "algorithm" header, leaving you scratching your head because you didn't=
=20
> really use any algorithms: you just tried to print a vector).
>
> But there are more dangerous problems, too. For example, if we merged thi=
s=20
> functionality into join(), then join() would have to return a proxy objec=
t=20
> that references the source range rather than a string. This may seem fine=
,=20
> especially if the proxy object has an implicit conversion to string, but:
>
> class team
> {
> public:
>   void add_player(string s) { players_.push_back(move(s)); }
>   void drop_player(string const& s) { players_.erase(find(players_.begin
> (), players_.end(), s)); }
>  =20
>   auto current_roster() const
>   {
>     // If join() returned a string - as currently spec'ed - no problems=
=20
> in this
>     // entire program. But if join() returns an adaptable proxy object=20
> with an
>     // implicit string conversion that lazy-evaluates....
>     return join(players_, ", ");
>   }
>  =20
> private:
>   vector<string> players_;
> };
>
> auto t =3D team{};
> t.add_player("Bruiser");
> t.add_player("T-bone");
>
> // No problems yet...
> auto s1 =3D std::string{};
> s1 =3D t.current_roster(); // proxy object implicit string conv gives=20
> "Bruiser, T-bone"
> cout << t.current_roster(); // proxy object prints "Bruiser, T-bone"
>
>
> // Uh oh!
> auto team_before =3D t.current_roster(); // proxy object references=20
> internal vector
>                                        // (contains: "Bruiser", "T-bone")
>
> t.drop_player("Bruiser");
> t.add_player("Stabby");
>
> // Proxy object team_before now references vector with "T-bone", "Stabby"=
!
>
> auto team_after =3D t.current_roster(); // proxy object references intern=
al=20
> vector
>                                       // (contains: "T-bone", "Stabby")
>
> cout << "Team before trade: " << team_before << '\n';
> cout << "Team after trade:  " << team_after << '\n';
> // Output is:
> // Team before trade: T-bone, Stabby
> // Team after trade:  T-bone, Stabby
>
> Try explaining that error to a beginner.
>
> What's happening here is that the proxy object that either streams or=20
> "strings" has to hold a reference to the original range. It can't copy it=
=20
> (that would be expensive), and it can't know until it is used whether it=
=20
> will be used to make a string or for streaming. Unless you explicitly cas=
t=20
> the result of join() to a string (or assign it to a string), you're getti=
ng=20
> the proxy object, which, with auto and return type deduction, means you m=
ay=20
> not be aware that you're trucking around a proxy object that probably hol=
ds=20
> a reference to the original range. If the original range goes out of scop=
e=20
> before the proxy object (and the example above can be easily modified to=
=20
> demonstrate that), bang. Even if it doesn't, you can get surprising=20
> results, as shown above.
>
> Between this and the problem of which header to put join() in, I just=20
> can't see a way to resolve the two different types of functionality down =
to=20
> a single function. Consider the following two statements:
>
> cout << "{ " << join(v, ", ") << " }";
> cout << "{ " << stream_range(v, ", ") << " }";
>
> They both look the same, and they both give identical results... but they=
=20
> do it in very, very different ways under the hood (in this case, join()=
=20
> would probably be quite inefficient compared to stream_range() - in=20
> non-streaming cases, the opposite would be true). It is not inconceivable=
=20
> that a programmer might want to insist on the behaviour of the first=20
> statement or the second - taking away the option of choosing what they wa=
nt=20
> (or at least making it more difficult to do so) seems counterproductive.=
=20
> And more importantly, they are both very different types of tasks. The=20
> former is to join the elements of the range into an object that you can=
=20
> hold on to and pass around (a string, in this case), while the latter is =
to=20
> coordinate output in a stream expression and is not intended to create a=
=20
> new, independent object. Strings and streams are just too different for=
=20
> there to be a single function to handle both. The apparent similarities a=
re=20
> just superficial.
>
> Which is too bad - I would have liked to use "join" (rather than=20
> "stream_range").
> =20
>
>> I'm sceptical to the idea of a input function receiving into a range, as=
=20
>> the typical use case is to not know the length in advance, and it is ver=
y=20
>> logical to a programmer to just state "push back the incoming things int=
o=20
>> this container, please".
>>
>
> My intention is to ultimately have a family of functions for input - the=
=20
> only one I've done so far is the one that overwrites a range with input=
=20
> values.
>
> I don't think it's that rare to want to read a known number of values int=
o=20
> a range, and there is currently no way to do it without manually writing =
a=20
> loop. You can't use copy_n() with an istream iterator, because it doesn't=
=20
> check for EOF (or any problems, really) - if the input stream goes bad=20
> halfway through, you end up with your container half-full of garbage=20
> (likely the last properly read value repeated). I don't think it's that=
=20
> rare to have an object of fixed size and to expect to read exactly that=
=20
> many values (for example, reading a 3d transformation matrix - it's alway=
s=20
> going to be 16 elements), or to have input that gives the number of items=
=20
> in a list before the list itself (that's a rather common file structure,=
=20
> really).
>
> Also, consider buffering. One of the ideas I'm toying with is to have the=
=20
> proxy object have a count() function, giving the number of items=20
> successfully written/read (and maybe a reset() function to reset it to 0)=
..=20
> So suppose you have a huge dataset - you can read in 100 values at a time=
=20
> and work with them like this:
>
> auto buffer =3D std::array<double, 100>{};
>
> while (in)
> {
>   auto p =3D std::stream_range(buffer);
>   in >> p; // That's it for input! This will attempt to read 100 doubles,=
=20
> and
>            // it will stop early and gracefully if it can't.
>  =20
>   if (p.count())
>   {
>     auto working_range =3D make_range(begin(buffer), next(begin(buffer), =
p.
> count()));
>    =20
>     // Now do your calculations with whatever was read in.
>   }
>  =20
>   // Or instead of the if block above, you can do:
>   // auto working_range =3D make_range(begin(buffer), next(begin(buffer),=
=20
> p.count()));
>   // if (!empty(working_range)) { ... }
> }
>
> While reading into an expanding range should be an option, I don't think=
=20
> it should be the only option. Expanding is expensive and not fail-safe, s=
o=20
> in cases where you can know the number of items to read before reading, y=
ou=20
> should always prefer to at least reserve() the space, if not straight-up=
=20
> create the receiving range already properly sized then read into it.
>
> Once I work out the wrinkles, I am going to add 3 more functions, which I=
=20
> am currently calling stream_range_back_insert(),=20
> stream_range_front_insert(), and stream_range_insert(), but which could=
=20
> just as well be called back_insert(), front_insert(), and insert(), becau=
se=20
> this is the only possible context where they can take 1, 1, and 2 argumen=
ts=20
> respectively. They would handle the case where you don't know the number =
of=20
> elements beforehand:
>
> std::cin >> std::stream_range(v); // Replaces all elements of v with=20
> input.
>
> std::cin >> std::back_insert(v); // Adds elements using v.push_back(x).
> std::cin >> std::front_insert(v); // Adds elements using v.push_front(x).
> std::cin >> std::insert(v, i); // Adds elements using v.insert(i, x).
>
> // In all cases above, input stops when bool(std::cin) is false.
> // If you want to know how many items were actually successfully read (on=
ly
> // relevant in the first case, really), you should do:
> // auto p =3D std::stream_range(v); // or whichever function you wish to =
use
> // std::cin >> p;
> // And the number of successfully read items is in p.count().
>
> At the moment I'm not concerned with the names - that can be dealt with=
=20
> later. (For example, maybe "overwrite" could be used for the first case=
=20
> above, and "output" or "write_all" could be used for the ostream version.=
)=20
> I'm more concerned with making this as flexible as possible, while keepin=
g=20
> it easy to use. One of the things I'm most concerned with is adding means=
=20
> to detect if and - more importantly - when I/O failed. That's something=
=20
> that no current method (using stream iterators or algorithms like copy)=
=20
> does, and unfortunately, split() doesn't seem equipped to do it either=20
> (along with its other issues, like being in the algorithms library).
> =20
>
>> It could be worth investigating if join() should be elaborated with some=
=20
>> more options like split(), for instance to handle a limited line length =
or=20
>> n-items per row printout, as well as maybe fixed width comlumns with spa=
ce=20
>> fill and things like that.
>>
>
> That seems like going way beyond the mandate of a simple range streaming=
=20
> facility. Those things might be useful (though I'm not particularly sure=
=20
> that standardizing a pretty-printing text output library is worth the=20
> effort in an age of graphical UIs), but the sheer number of permutations =
of=20
> reasonable options is just too much to even begin to consider for a basic=
=20
> function.
>
> If this is worth investigating (I'm not convinced), it should be=20
> investigated as an entirely separate library, because it isn't really=20
> related to ranges or streaming ranges.
> =20
>
>> An alternative is to let split() without the string parameter return a=
=20
>> helper object with an overloaded >> from istream, which does the work:
>>
>
> As far as I know, split() is defined as taking a source string(view) and =
a=20
> delimiter - it doesn't take the output range, it returns a proxy object=
=20
> made up of string_views into the original string. Have there been changes=
=20
> since N3593? Because if not, with that interface, there's really no way t=
o=20
> handle both "regular" splitting, and "splitting" from an input stream.
>

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

------=_Part_206_2030496647.1406019692182
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">A proposal to define an "operator auto" so that a class wi=
th "lazy" semantics can be instructed to convert to a certain type (in this=
 case string) when "converted to auto", such as in your function current_ro=
ster. I think is a typical usecase for that functionality... Unfortunately =
I forgot the exact syntax proposed but it was something like: auto operator=
 &lt;type&gt;() {} or &lt;type&gt; operator auto() {}<div><br></div><div>I =
think you got things messed up in your comparison of join() and stream_rang=
e() in the ostream shift example: The sole reason for having a proxy object=
 and getting the (now solved) problem with the hidden proxy object was that=
 this proxy object can be the rhs of a &lt;&lt; operator without the interv=
eaning conversion to string! Now you claim the performance penalty of join =
is still there. Maybe this was under the assumption that a proxy object wou=
ld be unacceptable and thus join just returning string... For the programme=
r join seems to return string and the proxy object is only a QoI possibilit=
y (although the committe will probably see issues with leaving the existanc=
e of the proxy object up to the implementation).</div><div><br></div><div>I=
 didn't chcek N3593 again, I was just assuming it took the output sequence =
as an object to be able to use different types of containers. But all right=
, as the element type is string_view that would rather be a template templa=
te parameter to indicate what type of container you want back. As &gt;&gt; =
operators return the istream split can of course not return the container o=
f parts too. But a split taking an istream as parameter would still be poss=
ible, although it would have to return a vector&lt;string&gt; instead of ve=
ctor&lt;string_view&gt;. Also I missed the rather obvious difference that s=
plit can't convert the parts to something else than strings... What I was a=
fter was the rather neat (albeit intricate) ways you can specify the delimi=
ting in that proposal (and also counts). I still think that synergy should =
be used. I don't see the problem with the algorithm header as any other hea=
der using it would of course include it. That is, unless you are worried ab=
out compile times.</div><div><br></div><div>But you may be right in that th=
e istream shifting into a container is important enough to warrant a separa=
te functionality. I don't like the separate function names though, and offe=
r that the basic function could take a template template parameter which de=
faults to back_inserter. A "overwriting" inserter would be used to handle y=
our range case (where you use stream_range). The naming is a later issue bu=
t insert is a bit odd. elements_of() reads better in context, I think:</div=
><div><br></div><div>cin &gt;&gt; elements_of(v); &nbsp; &nbsp; &nbsp; &nbs=
p; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &n=
bsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Uses back_i=
nserter as expected as default</div><div>cin &gt;&gt; elements_of&lt;front_=
inserter&gt;(v); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &n=
bsp; &nbsp; &nbsp;// Puts the elements first (in reverse order???)</div><di=
v>cin &gt;&gt; elements_of&lt;inserter&gt;(v, next(v, 10)); &nbsp; &nbsp; &=
nbsp; &nbsp; &nbsp; &nbsp;// Puts the elements at index 10 (not in reverse =
order I assume)</div><div>cin &gt;&gt; elements_of&lt;replacer&gt;(v, next(=
v, 10), next(v, 20)); // Replaces up to 10 elements of v. I think y proper =
overloading and maybe enable_if we can get rid of the redundant 'v' paramet=
er here.</div><div><br></div><div>The idea of giving the proxy object retur=
ned by elements_of a name and allow it to return the count is still valid a=
s you indicated.</div><div><br></div><div>What remains is how to convey the=
 insert position for the "center insert" case and a possibility to send in =
a subrange of a container to the "replacer" version. I propose to solve thi=
s using an additional parameter pack forwarded to the inserter:</div><div><=
br></div><div>template&lt;template&lt;typename&gt; inserter, typename C, ty=
pename... Ps&gt; _unspecified_ element_of(C&amp; container, Ps&amp;&amp; ps=
) { return _unspecified_&lt;inserter&lt;typename C::value_type&gt;&gt;(inse=
rter&lt;typename C::value_type&gt;(C, ps...)); }</div><div><br></div><div><=
br></div><div><div><br>Den m=C3=A5ndagen den 21:e juli 2014 kl. 01:44:38 UT=
C+2 skrev Mark A. Gibbs:<blockquote class=3D"gmail_quote" style=3D"margin: =
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div d=
ir=3D"ltr">On Sunday, 20 July 2014 14:58:45 UTC-4, Bengt Gustafsson  wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;borde=
r-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>I think these=
 two suggestions should be=20
synchronized so that we get one functionaliy which can do both input and
 output between a string or stream and a &nbsp;container or range, and whic=
h=20
includes the splitting options offered by the split proposal.</div></div></=
blockquote><div><br>When I first read your suggestions, I thought that woul=
d be the perfect solution - not only would it eliminate the need for anothe=
r standard library name (I've been using "stream_range", which is clunky), =
it would create a single interface to do what seem to be similar jobs.<br><=
br>But the more I thought about it, the more I realized this would be a mis=
take. While the operations of join() and stream_range() seem superficially =
similar from a really distant perspective, there are enough subtle differen=
ces in the practical application and the ways these functions will probably=
 be used to make it impossible to use the same function for both jobs. Also=
, it would essentially just be reinventing the same problem that inspired m=
e to make the suggestion in the first place - it shouldn't be necessary to =
include the algorithms library to do basic I/O, and streaming a range shoul=
d be basic I/O (put yourself in the shoes of a beginner who has just writte=
n a simple C++ program that includes the vector header and the iostream hea=
der, then does nothing in main but create a vector v and try to write it wi=
th "std::cout &lt;&lt; std::stream_range(v);"... only to discover the progr=
am won't compile because you're missing the "algorithm" header, leaving you=
 scratching your head because you didn't really use any algorithms: you jus=
t tried to print a vector).<br><br>But there are more dangerous problems, t=
oo. For example, if we merged this functionality into join(), then join() w=
ould have to return a proxy object that references the source range rather =
than a string. This may seem fine, especially if the proxy object has an im=
plicit conversion to string, but:<br><br><div style=3D"background-color:rgb=
(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-width=
:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">class</spa=
n><span style=3D"color:#000"> team<br></span><span style=3D"color:#660">{</=
span><span style=3D"color:#000"><br></span><span style=3D"color:#008">publi=
c</span><span style=3D"color:#660">:</span><span style=3D"color:#000"><br>&=
nbsp; </span><span style=3D"color:#008">void</span><span style=3D"color:#00=
0"> add_player</span><span style=3D"color:#660">(</span><span style=3D"colo=
r:#008">string</span><span style=3D"color:#000"> s</span><span style=3D"col=
or:#660">)</span><span style=3D"color:#000"> </span><span style=3D"color:#6=
60">{</span><span style=3D"color:#000"> players_</span><span style=3D"color=
:#660">.</span><span style=3D"color:#000">push_back</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">move</span><span style=3D"colo=
r:#660">(</span><span style=3D"color:#000">s</span><span style=3D"color:#66=
0">));</span><span style=3D"color:#000"> </span><span style=3D"color:#660">=
}</span><span style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#=
008">void</span><span style=3D"color:#000"> drop_player</span><span style=
=3D"color:#660">(</span><span style=3D"color:#008">string</span><span style=
=3D"color:#000"> </span><span style=3D"color:#008">const</span><span style=
=3D"color:#660">&amp;</span><span style=3D"color:#000"> s</span><span style=
=3D"color:#660">)</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#660">{</span><span style=3D"color:#000"> players_</span><span style=
=3D"color:#660">.</span><span style=3D"color:#000">erase</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">find</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">players_</span><span sty=
le=3D"color:#660">.</span><span style=3D"color:#008">b<wbr>egin</span><span=
 style=3D"color:#660">(),</span><span style=3D"color:#000"> players_</span>=
<span style=3D"color:#660">.</span><span style=3D"color:#008">end</span><sp=
an style=3D"color:#660">(),</span><span style=3D"color:#000"> s</span><span=
 style=3D"color:#660">));</span><span style=3D"color:#000"> </span><span st=
yle=3D"color:#660">}</span><span style=3D"color:#000"><br>&nbsp; <br>&nbsp;=
 </span><span style=3D"color:#008">auto</span><span style=3D"color:#000"> c=
urrent_roster</span><span style=3D"color:#660">()</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#008">const</span><span style=3D"color=
:#000"><br>&nbsp; </span><span style=3D"color:#660">{</span><span style=3D"=
color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#800">// If join(=
) returned a string - as currently spec'ed - no problems in this</span><spa=
n style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#800">=
// entire program. But if join() returns an adaptable proxy object with an<=
/span><span style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"co=
lor:#800">// implicit string conversion that lazy-evaluates....</span><span=
 style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#008">r=
eturn</span><span style=3D"color:#000"> join</span><span style=3D"color:#66=
0">(</span><span style=3D"color:#000">players_</span><span style=3D"color:#=
660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#080">=
", "</span><span style=3D"color:#660">);</span><span style=3D"color:#000"><=
br>&nbsp; </span><span style=3D"color:#660">}</span><span style=3D"color:#0=
00"><br>&nbsp; <br></span><span style=3D"color:#008">private</span><span st=
yle=3D"color:#660">:</span><span style=3D"color:#000"><br>&nbsp; vector</sp=
an><span style=3D"color:#080">&lt;string&gt;</span><span style=3D"color:#00=
0"> players_</span><span style=3D"color:#660">;</span><span style=3D"color:=
#000"><br></span><span style=3D"color:#660">};</span><span style=3D"color:#=
000"><br><br></span><span style=3D"color:#008">auto</span><span style=3D"co=
lor:#000"> t </span><span style=3D"color:#660">=3D</span><span style=3D"col=
or:#000"> team</span><span style=3D"color:#660">{};</span><span style=3D"co=
lor:#000"><br>t</span><span style=3D"color:#660">.</span><span style=3D"col=
or:#000">add_player</span><span style=3D"color:#660">(</span><span style=3D=
"color:#080">"Bruiser"</span><span style=3D"color:#660">);</span><span styl=
e=3D"color:#000"><br>t</span><span style=3D"color:#660">.</span><span style=
=3D"color:#000">add_player</span><span style=3D"color:#660">(</span><span s=
tyle=3D"color:#080">"T-bone"</span><span style=3D"color:#660">);</span><spa=
n style=3D"color:#000"><br><br></span><span style=3D"color:#800">// No prob=
lems yet...</span><span style=3D"color:#000"><br></span><span style=3D"colo=
r:#008">auto</span><span style=3D"color:#000"> s1 </span><span style=3D"col=
or:#660">=3D</span><span style=3D"color:#000"> std</span><span style=3D"col=
or:#660">::</span><span style=3D"color:#008">string</span><span style=3D"co=
lor:#660">{};</span><span style=3D"color:#000"><br>s1 </span><span style=3D=
"color:#660">=3D</span><span style=3D"color:#000"> t</span><span style=3D"c=
olor:#660">.</span><span style=3D"color:#000">current_roster</span><span st=
yle=3D"color:#660">();</span><span style=3D"color:#000"> </span><span style=
=3D"color:#800">// proxy object implicit string conv gives "Bruiser, T-bone=
"</span><span style=3D"color:#000"><br>cout </span><span style=3D"color:#66=
0">&lt;&lt;</span><span style=3D"color:#000"> t</span><span style=3D"color:=
#660">.</span><span style=3D"color:#000">current_roster</span><span style=
=3D"color:#660">();</span><span style=3D"color:#000"> </span><span style=3D=
"color:#800">// proxy object prints "Bruiser, T-bone"</span><span style=3D"=
color:#000"><br><br><br></span><span style=3D"color:#800">// Uh oh!</span><=
span style=3D"color:#000"><br></span><span style=3D"color:#008">auto</span>=
<span style=3D"color:#000"> team_before </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> t</span><span style=3D"color:#660">.<=
/span><span style=3D"color:#000">current_roster</span><span style=3D"color:=
#660">();</span><span style=3D"color:#000"> </span><span style=3D"color:#80=
0">// proxy object references internal vector</span><span style=3D"color:#0=
00"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbs=
p; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</s=
pan><span style=3D"color:#800">// (contains: "Bruiser", "T-bone")</span><sp=
an style=3D"color:#000"><br><br>t</span><span style=3D"color:#660">.</span>=
<span style=3D"color:#000">drop_player</span><span style=3D"color:#660">(</=
span><span style=3D"color:#080">"Bruiser"</span><span style=3D"color:#660">=
);</span><span style=3D"color:#000"><br>t</span><span style=3D"color:#660">=
..</span><span style=3D"color:#000">add_player</span><span style=3D"color:#6=
60">(</span><span style=3D"color:#080">"Stabby"</span><span style=3D"color:=
#660">);</span><span style=3D"color:#000"><br><br></span><span style=3D"col=
or:#800">// Proxy object team_before now references vector with "T-bone", "=
Stabby"!</span><span style=3D"color:#000"><br><br></span><span style=3D"col=
or:#008">auto</span><span style=3D"color:#000"> team_after </span><span sty=
le=3D"color:#660">=3D</span><span style=3D"color:#000"> t</span><span style=
=3D"color:#660">.</span><span style=3D"color:#000">current_roster</span><sp=
an style=3D"color:#660">();</span><span style=3D"color:#000"> </span><span =
style=3D"color:#800">// proxy object references internal vector</span><span=
 style=3D"color:#000"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp=
; &nbsp; </span><span style=3D"color:#800">// (contains: "T-bone", "Stabby"=
)</span><span style=3D"color:#000"><br><br>cout </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#080">"Team before trade: "</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> team_bef=
ore </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#=
000"> </span><span style=3D"color:#080">'\n'</span><span style=3D"color:#66=
0">;</span><span style=3D"color:#000"><br>cout </span><span style=3D"color:=
#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"colo=
r:#080">"Team after trade: &nbsp;"</span><span style=3D"color:#000"> </span=
><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> team=
_after </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#080">'\n'</span><span style=3D"color:=
#660">;</span><span style=3D"color:#000"><br></span><span style=3D"color:#8=
00">// Output is:</span><span style=3D"color:#000"><br></span><span style=
=3D"color:#800">// Team before trade: T-bone, Stabby</span><span style=3D"c=
olor:#000"><br></span><span style=3D"color:#800">// Team after trade: &nbsp=
;T-bone, Stabby</span></div></code></div><br>Try explaining that error to a=
 beginner.<br><br>What's happening here is that the proxy object that eithe=
r streams or "strings" has to hold a reference to the original range. It ca=
n't copy it (that would be expensive), and it can't know until it is used w=
hether it will be used to make a string or for streaming. Unless you explic=
itly cast the result of join() to a string (or assign it to a string), you'=
re getting the proxy object, which, with auto and return type deduction, me=
ans you may not be aware that you're trucking around a proxy object that pr=
obably holds a reference to the original range. If the original range goes =
out of scope before the proxy object (and the example above can be easily m=
odified to demonstrate that), bang. Even if it doesn't, you can get surpris=
ing results, as shown above.<br><br>Between this and the problem of which h=
eader to put join() in, I just can't see a way to resolve the two different=
 types of functionality down to a single function. Consider the following t=
wo statements:<br><br><div style=3D"background-color:rgb(250,250,250);borde=
r-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:brea=
k-word"><code><div><span style=3D"color:#000">cout </span><span style=3D"co=
lor:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"=
color:#080">"{ "</span><span style=3D"color:#000"> </span><span style=3D"co=
lor:#660">&lt;&lt;</span><span style=3D"color:#000"> join</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">v</span><span style=3D"c=
olor:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:=
#080">", "</span><span style=3D"color:#660">)</span><span style=3D"color:#0=
00"> </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:=
#000"> </span><span style=3D"color:#080">" }"</span><span style=3D"color:#6=
60">;</span><span style=3D"color:#000"><br>cout </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#080">"{ "</span><span style=3D"color:#000"> </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> stream_range</span><span =
style=3D"color:#660">(</span><span style=3D"color:#000">v</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#080">", "</span><span style=3D"color:#660">)</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"c=
olor:#000"> </span><span style=3D"color:#080">" }"</span><span style=3D"col=
or:#660">;</span></div></code></div><br>They both look the same, and they b=
oth give identical results... but they do it in very, very different ways u=
nder the hood (in this case, join() would probably be quite inefficient com=
pared to stream_range() - in non-streaming cases, the opposite would be tru=
e). It is not inconceivable that a programmer might want to insist on the b=
ehaviour of the first statement or the second - taking away the option of c=
hoosing what they want (or at least making it more difficult to do so) seem=
s counterproductive. And more importantly, they are both very different typ=
es of tasks. The former is to join the elements of the range into an object=
 that you can hold on to and pass around (a string, in this case), while th=
e latter is to coordinate output in a stream expression and is not intended=
 to create a new, independent object. Strings and streams are just too diff=
erent for there to be a single function to handle both. The apparent simila=
rities are just superficial.<br><br>Which is too bad - I would have liked t=
o use "join" (rather than "stream_range").<br>&nbsp;</div><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr">I'm sceptical to the idea of a inpu=
t function receiving into a range, as the typical use case is to not know t=
he length in advance, and it is very logical to a programmer to just state =
"push back the incoming things into this container, please".</div></blockqu=
ote><div><br>My intention is to ultimately have a family of functions for i=
nput - the only one I've done so far is the one that overwrites a range wit=
h input values.<br><br>I don't think it's that rare to want to read a known=
 number of values into a range, and there is currently no way to do it with=
out manually writing a loop. You can't use copy_n() with an istream iterato=
r, because it doesn't check for EOF (or any problems, really) - if the inpu=
t stream goes bad halfway through, you end up with your container half-full=
 of garbage (likely the last properly read value repeated). I don't think i=
t's that rare to have an object of fixed size and to expect to read exactly=
 that many values (for example, reading a 3d transformation matrix - it's a=
lways going to be 16 elements), or to have input that gives the number of i=
tems in a list before the list itself (that's a rather common file structur=
e, really).<br><br>Also, consider buffering. One of the ideas I'm toying wi=
th is to have the proxy object have a count() function, giving the number o=
f items successfully written/read (and maybe a reset() function to reset it=
 to 0). So suppose you have a huge dataset - you can read in 100 values at =
a time and work with them like this:<br><br><div style=3D"background-color:=
rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-wi=
dth:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">auto</s=
pan><span style=3D"color:#000"> buffer </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> std</span><span style=3D"color:#660">=
::</span><span style=3D"color:#000">array</span><span style=3D"color:#660">=
&lt;</span><span style=3D"color:#008">double</span><span style=3D"color:#66=
0">,</span><span style=3D"color:#000"> </span><span style=3D"color:#066">10=
0</span><span style=3D"color:#660">&gt;{};</span><span style=3D"color:#000"=
><br><br></span><span style=3D"color:#008">while</span><span style=3D"color=
:#000"> </span><span style=3D"color:#660">(</span><span style=3D"color:#008=
">in</span><span style=3D"color:#660">)</span><span style=3D"color:#000"><b=
r></span><span style=3D"color:#660">{</span><span style=3D"color:#000"><br>=
&nbsp; </span><span style=3D"color:#008">auto</span><span style=3D"color:#0=
00"> p </span><span style=3D"color:#660">=3D</span><span style=3D"color:#00=
0"> std</span><span style=3D"color:#660">::</span><span style=3D"color:#000=
">stream_range</span><span style=3D"color:#660">(</span><span style=3D"colo=
r:#000">buffer</span><span style=3D"color:#660">);</span><span style=3D"col=
or:#000"><br>&nbsp; </span><span style=3D"color:#008">in</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">&gt;&gt;</span><span sty=
le=3D"color:#000"> p</span><span style=3D"color:#660">;</span><span style=
=3D"color:#000"> </span><span style=3D"color:#800">// That's it for input! =
This will attempt to read 100 doubles, and</span><span style=3D"color:#000"=
><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style=3D"color:#=
800">// it will stop early and gracefully if it can't.</span><span style=3D=
"color:#000"><br>&nbsp; <br>&nbsp; </span><span style=3D"color:#008">if</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#660">(</span><s=
pan style=3D"color:#000">p</span><span style=3D"color:#660">.</span><span s=
tyle=3D"color:#000">count</span><span style=3D"color:#660">())</span><span =
style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#660">{</span><=
span style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#00=
8">auto</span><span style=3D"color:#000"> working_range </span><span style=
=3D"color:#660">=3D</span><span style=3D"color:#000"> make_range</span><spa=
n style=3D"color:#660">(</span><span style=3D"color:#008">begin</span><span=
 style=3D"color:#660">(</span><span style=3D"color:#000">buffer</span><span=
 style=3D"color:#660">),</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#008">next</span><span style=3D"color:#660">(</span><span style=
=3D"color:#008">begin</span><span style=3D"color:#660">(</span><span style=
=3D"color:#000">buffer</span><span style=3D"color:#660">),</span><span styl=
e=3D"color:#000"> p</span><span style=3D"color:#660">.</span><span style=3D=
"color:#000">count</span><span style=3D"color:#660">()));</span><span style=
=3D"color:#000"><br>&nbsp; &nbsp; <br>&nbsp; &nbsp; </span><span style=3D"c=
olor:#800">// Now do your calculations with whatever was read in.</span><sp=
an style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#660">}</spa=
n><span style=3D"color:#000"><br>&nbsp; <br>&nbsp; </span><span style=3D"co=
lor:#800">// Or instead of the if block above, you can do:</span><span styl=
e=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#800">// auto worki=
ng_range =3D make_range(begin(buffer), next(begin(buffer), p.count()));</sp=
an><span style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#800">=
// if (!empty(working_range)) { ... }</span><span style=3D"color:#000"><br>=
</span><span style=3D"color:#660">}</span></div></code></div><br>While read=
ing into an expanding range should be an option, I don't think it should be=
 the only option. Expanding is expensive and not fail-safe, so in cases whe=
re you can know the number of items to read before reading, you should alwa=
ys prefer to at least reserve() the space, if not straight-up create the re=
ceiving range already properly sized then read into it.<br><br>Once I work =
out the wrinkles, I am going to add 3 more functions, which I am currently =
calling stream_range_back_insert(), stream_range_front_insert(), and stream=
_range_insert(), but which could just as well be called back_insert(), fron=
t_insert(), and insert(), because this is the only possible context where t=
hey can take 1, 1, and 2 arguments respectively. They would handle the case=
 where you don't know the number of elements beforehand:<br><br><div style=
=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-=
style:solid;border-width:1px;word-wrap:break-word"><code><div><span style=
=3D"color:#000">std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#000">cin </span><span style=3D"color:#660">&gt;&gt;</span><span =
style=3D"color:#000"> std</span><span style=3D"color:#660">::</span><span s=
tyle=3D"color:#000">stream_range</span><span style=3D"color:#660">(</span><=
span style=3D"color:#000">v</span><span style=3D"color:#660">);</span><span=
 style=3D"color:#000"> </span><span style=3D"color:#800">// Replaces all el=
ements of v with input.</span><span style=3D"color:#000"><br><br>std</span>=
<span style=3D"color:#660">::</span><span style=3D"color:#000">cin </span><=
span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> std</s=
pan><span style=3D"color:#660">::</span><span style=3D"color:#000">back_ins=
ert</span><span style=3D"color:#660">(</span><span style=3D"color:#000">v</=
span><span style=3D"color:#660">);</span><span style=3D"color:#000"> </span=
><span style=3D"color:#800">// Adds elements using v.push_back(x).</span><s=
pan style=3D"color:#000"><br>std</span><span style=3D"color:#660">::</span>=
<span style=3D"color:#000">cin </span><span style=3D"color:#660">&gt;&gt;</=
span><span style=3D"color:#000"> std</span><span style=3D"color:#660">::</s=
pan><span style=3D"color:#000">front_insert</span><span style=3D"color:#660=
">(</span><span style=3D"color:#000">v</span><span style=3D"color:#660">);<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#800">// Adds=
 elements using v.push_front(x).</span><span style=3D"color:#000"><br>std</=
span><span style=3D"color:#660">::</span><span style=3D"color:#000">cin </s=
pan><span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> s=
td</span><span style=3D"color:#660">::</span><span style=3D"color:#000">ins=
ert</span><span style=3D"color:#660">(</span><span style=3D"color:#000">v</=
span><span style=3D"color:#660">,</span><span style=3D"color:#000"> i</span=
><span style=3D"color:#660">);</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#800">// Adds elements using v.insert(i, x).</span><span =
style=3D"color:#000"><br><br></span><span style=3D"color:#800">// In all ca=
ses above, input stops when bool(std::cin) is false.</span><span style=3D"c=
olor:#000"><br></span><span style=3D"color:#800">// If you want to know how=
 many items were actually successfully read (only</span><span style=3D"colo=
r:#000"><br></span><span style=3D"color:#800">// relevant in the first case=
, really), you should do:</span><span style=3D"color:#000"><br></span><span=
 style=3D"color:#800">// auto p =3D std::stream_range(v); // or whichever f=
unction you wish to use</span><span style=3D"color:#000"><br></span><span s=
tyle=3D"color:#800">// std::cin &gt;&gt; p;</span><span style=3D"color:#000=
"><br></span><span style=3D"color:#800">// And the number of successfully r=
ead items is in p.count().</span></div></code></div><br>At the moment I'm n=
ot concerned with the names - that can be dealt with later. (For example, m=
aybe "overwrite" could be used for the first case above, and "output" or "w=
rite_all" could be used for the ostream version.) I'm more concerned with m=
aking this as flexible as possible, while keeping it easy to use. One of th=
e things I'm most concerned with is adding means to detect if and - more im=
portantly - when I/O failed. That's something that no current method (using=
 stream iterators or algorithms like copy) does, and unfortunately, split()=
 doesn't seem equipped to do it either (along with its other issues, like b=
eing in the algorithms library).<br>&nbsp;</div><blockquote class=3D"gmail_=
quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddi=
ng-left:1ex"><div dir=3D"ltr"> <div>It could be worth investigating if join=
() should be elaborated with some more options like split(), for instance t=
o handle a limited line length or n-items per row printout, as well as mayb=
e fixed width comlumns with space fill and things like that.</div></div></b=
lockquote><div><br>That seems like going way beyond the mandate of a simple=
 range streaming facility. Those things might be useful (though I'm not par=
ticularly sure that standardizing a pretty-printing text output library is =
worth the effort in an age of graphical UIs), but the sheer number of permu=
tations of reasonable options is just too much to even begin to consider fo=
r a basic function.<br><br>If this is worth investigating (I'm not convince=
d), it should be investigated as an entirely separate library, because it i=
sn't really related to ranges or streaming ranges.<br>&nbsp;</div><blockquo=
te class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>An alternative is to l=
et split() without the string parameter return a helper object with an over=
loaded &gt;&gt; from istream, which does the work:</div></div></blockquote>=
<div><br>As far as I know, split() is defined as taking a source string(vie=
w) and a delimiter - it doesn't take the output range, it returns a proxy o=
bject made up of string_views into the original string. Have there been cha=
nges since N3593? Because if not, with that interface, there's really no wa=
y to handle both "regular" splitting, and "splitting" from an input stream.=
</div></div></blockquote></div></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_206_2030496647.1406019692182--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Tue, 22 Jul 2014 06:40:27 -0700 (PDT)
Raw View
------=_Part_333_1185061530.1406036427324
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Here's the auto type paper:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4035.pdf



Den tisdagen den 22:e juli 2014 kl. 11:01:32 UTC+2 skrev Bengt Gustafsson:
>
> A proposal to define an "operator auto" so that a class with "lazy"=20
> semantics can be instructed to convert to a certain type (in this case=20
> string) when "converted to auto", such as in your function current_roster=
..=20
> I think is a typical usecase for that functionality... Unfortunately I=20
> forgot the exact syntax proposed but it was something like: auto operator=
=20
> <type>() {} or <type> operator auto() {}
>
> I think you got things messed up in your comparison of join() and=20
> stream_range() in the ostream shift example: The sole reason for having a=
=20
> proxy object and getting the (now solved) problem with the hidden proxy=
=20
> object was that this proxy object can be the rhs of a << operator without=
=20
> the interveaning conversion to string! Now you claim the performance=20
> penalty of join is still there. Maybe this was under the assumption that =
a=20
> proxy object would be unacceptable and thus join just returning string...=
=20
> For the programmer join seems to return string and the proxy object is on=
ly=20
> a QoI possibility (although the committe will probably see issues with=20
> leaving the existance of the proxy object up to the implementation).
>
> I didn't chcek N3593 again, I was just assuming it took the output=20
> sequence as an object to be able to use different types of containers. Bu=
t=20
> all right, as the element type is string_view that would rather be a=20
> template template parameter to indicate what type of container you want=
=20
> back. As >> operators return the istream split can of course not return t=
he=20
> container of parts too. But a split taking an istream as parameter would=
=20
> still be possible, although it would have to return a vector<string>=20
> instead of vector<string_view>. Also I missed the rather obvious differen=
ce=20
> that split can't convert the parts to something else than strings... What=
 I=20
> was after was the rather neat (albeit intricate) ways you can specify the=
=20
> delimiting in that proposal (and also counts). I still think that synergy=
=20
> should be used. I don't see the problem with the algorithm header as any=
=20
> other header using it would of course include it. That is, unless you are=
=20
> worried about compile times.
>
> But you may be right in that the istream shifting into a container is=20
> important enough to warrant a separate functionality. I don't like the=20
> separate function names though, and offer that the basic function could=
=20
> take a template template parameter which defaults to back_inserter. A=20
> "overwriting" inserter would be used to handle your range case (where you=
=20
> use stream_range). The naming is a later issue but insert is a bit odd.=
=20
> elements_of() reads better in context, I think:
>
> cin >> elements_of(v);                                               //=
=20
> Uses back_inserter as expected as default
> cin >> elements_of<front_inserter>(v);                      // Puts the=
=20
> elements first (in reverse order???)
> cin >> elements_of<inserter>(v, next(v, 10));            // Puts the=20
> elements at index 10 (not in reverse order I assume)
> cin >> elements_of<replacer>(v, next(v, 10), next(v, 20)); // Replaces up=
=20
> to 10 elements of v. I think y proper overloading and maybe enable_if we=
=20
> can get rid of the redundant 'v' parameter here.
>
> The idea of giving the proxy object returned by elements_of a name and=20
> allow it to return the count is still valid as you indicated.
>
> What remains is how to convey the insert position for the "center insert"=
=20
> case and a possibility to send in a subrange of a container to the=20
> "replacer" version. I propose to solve this using an additional parameter=
=20
> pack forwarded to the inserter:
>
> template<template<typename> inserter, typename C, typename... Ps>=20
> _unspecified_ element_of(C& container, Ps&& ps) { return=20
> _unspecified_<inserter<typename C::value_type>>(inserter<typename=20
> C::value_type>(C, ps...)); }
>
>
>
> Den m=C3=A5ndagen den 21:e juli 2014 kl. 01:44:38 UTC+2 skrev Mark A. Gib=
bs:
>>
>> On Sunday, 20 July 2014 14:58:45 UTC-4, Bengt Gustafsson wrote:
>>>
>>> I think these two suggestions should be synchronized so that we get one=
=20
>>> functionaliy which can do both input and output between a string or str=
eam=20
>>> and a  container or range, and which includes the splitting options off=
ered=20
>>> by the split proposal.
>>>
>>
>> When I first read your suggestions, I thought that would be the perfect=
=20
>> solution - not only would it eliminate the need for another standard=20
>> library name (I've been using "stream_range", which is clunky), it would=
=20
>> create a single interface to do what seem to be similar jobs.
>>
>> But the more I thought about it, the more I realized this would be a=20
>> mistake. While the operations of join() and stream_range() seem=20
>> superficially similar from a really distant perspective, there are enoug=
h=20
>> subtle differences in the practical application and the ways these=20
>> functions will probably be used to make it impossible to use the same=20
>> function for both jobs. Also, it would essentially just be reinventing t=
he=20
>> same problem that inspired me to make the suggestion in the first place =
-=20
>> it shouldn't be necessary to include the algorithms library to do basic=
=20
>> I/O, and streaming a range should be basic I/O (put yourself in the shoe=
s=20
>> of a beginner who has just written a simple C++ program that includes th=
e=20
>> vector header and the iostream header, then does nothing in main but cre=
ate=20
>> a vector v and try to write it with "std::cout << std::stream_range(v);"=
....=20
>> only to discover the program won't compile because you're missing the=20
>> "algorithm" header, leaving you scratching your head because you didn't=
=20
>> really use any algorithms: you just tried to print a vector).
>>
>> But there are more dangerous problems, too. For example, if we merged=20
>> this functionality into join(), then join() would have to return a proxy=
=20
>> object that references the source range rather than a string. This may s=
eem=20
>> fine, especially if the proxy object has an implicit conversion to strin=
g,=20
>> but:
>>
>> class team
>> {
>> public:
>>   void add_player(string s) { players_.push_back(move(s)); }
>>   void drop_player(string const& s) { players_.erase(find(players_.begin
>> (), players_.end(), s)); }
>>  =20
>>   auto current_roster() const
>>   {
>>     // If join() returned a string - as currently spec'ed - no problems=
=20
>> in this
>>     // entire program. But if join() returns an adaptable proxy object=
=20
>> with an
>>     // implicit string conversion that lazy-evaluates....
>>     return join(players_, ", ");
>>   }
>>  =20
>> private:
>>   vector<string> players_;
>> };
>>
>> auto t =3D team{};
>> t.add_player("Bruiser");
>> t.add_player("T-bone");
>>
>> // No problems yet...
>> auto s1 =3D std::string{};
>> s1 =3D t.current_roster(); // proxy object implicit string conv gives=20
>> "Bruiser, T-bone"
>> cout << t.current_roster(); // proxy object prints "Bruiser, T-bone"
>>
>>
>> // Uh oh!
>> auto team_before =3D t.current_roster(); // proxy object references=20
>> internal vector
>>                                        // (contains: "Bruiser", "T-bone"=
)
>>
>> t.drop_player("Bruiser");
>> t.add_player("Stabby");
>>
>> // Proxy object team_before now references vector with "T-bone", "Stabby=
"!
>>
>> auto team_after =3D t.current_roster(); // proxy object references=20
>> internal vector
>>                                       // (contains: "T-bone", "Stabby")
>>
>> cout << "Team before trade: " << team_before << '\n';
>> cout << "Team after trade:  " << team_after << '\n';
>> // Output is:
>> // Team before trade: T-bone, Stabby
>> // Team after trade:  T-bone, Stabby
>>
>> Try explaining that error to a beginner.
>>
>> What's happening here is that the proxy object that either streams or=20
>> "strings" has to hold a reference to the original range. It can't copy i=
t=20
>> (that would be expensive), and it can't know until it is used whether it=
=20
>> will be used to make a string or for streaming. Unless you explicitly ca=
st=20
>> the result of join() to a string (or assign it to a string), you're gett=
ing=20
>> the proxy object, which, with auto and return type deduction, means you =
may=20
>> not be aware that you're trucking around a proxy object that probably ho=
lds=20
>> a reference to the original range. If the original range goes out of sco=
pe=20
>> before the proxy object (and the example above can be easily modified to=
=20
>> demonstrate that), bang. Even if it doesn't, you can get surprising=20
>> results, as shown above.
>>
>> Between this and the problem of which header to put join() in, I just=20
>> can't see a way to resolve the two different types of functionality down=
 to=20
>> a single function. Consider the following two statements:
>>
>> cout << "{ " << join(v, ", ") << " }";
>> cout << "{ " << stream_range(v, ", ") << " }";
>>
>> They both look the same, and they both give identical results... but the=
y=20
>> do it in very, very different ways under the hood (in this case, join()=
=20
>> would probably be quite inefficient compared to stream_range() - in=20
>> non-streaming cases, the opposite would be true). It is not inconceivabl=
e=20
>> that a programmer might want to insist on the behaviour of the first=20
>> statement or the second - taking away the option of choosing what they w=
ant=20
>> (or at least making it more difficult to do so) seems counterproductive.=
=20
>> And more importantly, they are both very different types of tasks. The=
=20
>> former is to join the elements of the range into an object that you can=
=20
>> hold on to and pass around (a string, in this case), while the latter is=
 to=20
>> coordinate output in a stream expression and is not intended to create a=
=20
>> new, independent object. Strings and streams are just too different for=
=20
>> there to be a single function to handle both. The apparent similarities =
are=20
>> just superficial.
>>
>> Which is too bad - I would have liked to use "join" (rather than=20
>> "stream_range").
>> =20
>>
>>> I'm sceptical to the idea of a input function receiving into a range, a=
s=20
>>> the typical use case is to not know the length in advance, and it is ve=
ry=20
>>> logical to a programmer to just state "push back the incoming things in=
to=20
>>> this container, please".
>>>
>>
>> My intention is to ultimately have a family of functions for input - the=
=20
>> only one I've done so far is the one that overwrites a range with input=
=20
>> values.
>>
>> I don't think it's that rare to want to read a known number of values=20
>> into a range, and there is currently no way to do it without manually=20
>> writing a loop. You can't use copy_n() with an istream iterator, because=
 it=20
>> doesn't check for EOF (or any problems, really) - if the input stream go=
es=20
>> bad halfway through, you end up with your container half-full of garbage=
=20
>> (likely the last properly read value repeated). I don't think it's that=
=20
>> rare to have an object of fixed size and to expect to read exactly that=
=20
>> many values (for example, reading a 3d transformation matrix - it's alwa=
ys=20
>> going to be 16 elements), or to have input that gives the number of item=
s=20
>> in a list before the list itself (that's a rather common file structure,=
=20
>> really).
>>
>> Also, consider buffering. One of the ideas I'm toying with is to have th=
e=20
>> proxy object have a count() function, giving the number of items=20
>> successfully written/read (and maybe a reset() function to reset it to 0=
).=20
>> So suppose you have a huge dataset - you can read in 100 values at a tim=
e=20
>> and work with them like this:
>>
>> auto buffer =3D std::array<double, 100>{};
>>
>> while (in)
>> {
>>   auto p =3D std::stream_range(buffer);
>>   in >> p; // That's it for input! This will attempt to read 100=20
>> doubles, and
>>            // it will stop early and gracefully if it can't.
>>  =20
>>   if (p.count())
>>   {
>>     auto working_range =3D make_range(begin(buffer), next(begin(buffer),=
 p.
>> count()));
>>    =20
>>     // Now do your calculations with whatever was read in.
>>   }
>>  =20
>>   // Or instead of the if block above, you can do:
>>   // auto working_range =3D make_range(begin(buffer), next(begin(buffer)=
,=20
>> p.count()));
>>   // if (!empty(working_range)) { ... }
>> }
>>
>> While reading into an expanding range should be an option, I don't think=
=20
>> it should be the only option. Expanding is expensive and not fail-safe, =
so=20
>> in cases where you can know the number of items to read before reading, =
you=20
>> should always prefer to at least reserve() the space, if not straight-up=
=20
>> create the receiving range already properly sized then read into it.
>>
>> Once I work out the wrinkles, I am going to add 3 more functions, which =
I=20
>> am currently calling stream_range_back_insert(),=20
>> stream_range_front_insert(), and stream_range_insert(), but which could=
=20
>> just as well be called back_insert(), front_insert(), and insert(), beca=
use=20
>> this is the only possible context where they can take 1, 1, and 2 argume=
nts=20
>> respectively. They would handle the case where you don't know the number=
 of=20
>> elements beforehand:
>>
>> std::cin >> std::stream_range(v); // Replaces all elements of v with=20
>> input.
>>
>> std::cin >> std::back_insert(v); // Adds elements using v.push_back(x).
>> std::cin >> std::front_insert(v); // Adds elements using v.push_front(x)=
..
>> std::cin >> std::insert(v, i); // Adds elements using v.insert(i, x).
>>
>> // In all cases above, input stops when bool(std::cin) is false.
>> // If you want to know how many items were actually successfully read=20
>> (only
>> // relevant in the first case, really), you should do:
>> // auto p =3D std::stream_range(v); // or whichever function you wish to=
 use
>> // std::cin >> p;
>> // And the number of successfully read items is in p.count().
>>
>> At the moment I'm not concerned with the names - that can be dealt with=
=20
>> later. (For example, maybe "overwrite" could be used for the first case=
=20
>> above, and "output" or "write_all" could be used for the ostream version=
..)=20
>> I'm more concerned with making this as flexible as possible, while keepi=
ng=20
>> it easy to use. One of the things I'm most concerned with is adding mean=
s=20
>> to detect if and - more importantly - when I/O failed. That's something=
=20
>> that no current method (using stream iterators or algorithms like copy)=
=20
>> does, and unfortunately, split() doesn't seem equipped to do it either=
=20
>> (along with its other issues, like being in the algorithms library).
>> =20
>>
>>> It could be worth investigating if join() should be elaborated with som=
e=20
>>> more options like split(), for instance to handle a limited line length=
 or=20
>>> n-items per row printout, as well as maybe fixed width comlumns with sp=
ace=20
>>> fill and things like that.
>>>
>>
>> That seems like going way beyond the mandate of a simple range streaming=
=20
>> facility. Those things might be useful (though I'm not particularly sure=
=20
>> that standardizing a pretty-printing text output library is worth the=20
>> effort in an age of graphical UIs), but the sheer number of permutations=
 of=20
>> reasonable options is just too much to even begin to consider for a basi=
c=20
>> function.
>>
>> If this is worth investigating (I'm not convinced), it should be=20
>> investigated as an entirely separate library, because it isn't really=20
>> related to ranges or streaming ranges.
>> =20
>>
>>> An alternative is to let split() without the string parameter return a=
=20
>>> helper object with an overloaded >> from istream, which does the work:
>>>
>>
>> As far as I know, split() is defined as taking a source string(view) and=
=20
>> a delimiter - it doesn't take the output range, it returns a proxy objec=
t=20
>> made up of string_views into the original string. Have there been change=
s=20
>> since N3593? Because if not, with that interface, there's really no way =
to=20
>> handle both "regular" splitting, and "splitting" from an input stream.
>>
>

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

------=_Part_333_1185061530.1406036427324
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Here's the auto type paper:<div><br></div><div>http://www.=
open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4035.pdf</div><div><br></div>=
<div><br><br>Den tisdagen den 22:e juli 2014 kl. 11:01:32 UTC+2 skrev Bengt=
 Gustafsson:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">A=
 proposal to define an "operator auto" so that a class with "lazy" semantic=
s can be instructed to convert to a certain type (in this case string) when=
 "converted to auto", such as in your function current_roster. I think is a=
 typical usecase for that functionality... Unfortunately I forgot the exact=
 syntax proposed but it was something like: auto operator &lt;type&gt;() {}=
 or &lt;type&gt; operator auto() {}<div><br></div><div>I think you got thin=
gs messed up in your comparison of join() and stream_range() in the ostream=
 shift example: The sole reason for having a proxy object and getting the (=
now solved) problem with the hidden proxy object was that this proxy object=
 can be the rhs of a &lt;&lt; operator without the interveaning conversion =
to string! Now you claim the performance penalty of join is still there. Ma=
ybe this was under the assumption that a proxy object would be unacceptable=
 and thus join just returning string... For the programmer join seems to re=
turn string and the proxy object is only a QoI possibility (although the co=
mmitte will probably see issues with leaving the existance of the proxy obj=
ect up to the implementation).</div><div><br></div><div>I didn't chcek N359=
3 again, I was just assuming it took the output sequence as an object to be=
 able to use different types of containers. But all right, as the element t=
ype is string_view that would rather be a template template parameter to in=
dicate what type of container you want back. As &gt;&gt; operators return t=
he istream split can of course not return the container of parts too. But a=
 split taking an istream as parameter would still be possible, although it =
would have to return a vector&lt;string&gt; instead of vector&lt;string_vie=
w&gt;. Also I missed the rather obvious difference that split can't convert=
 the parts to something else than strings... What I was after was the rathe=
r neat (albeit intricate) ways you can specify the delimiting in that propo=
sal (and also counts). I still think that synergy should be used. I don't s=
ee the problem with the algorithm header as any other header using it would=
 of course include it. That is, unless you are worried about compile times.=
</div><div><br></div><div>But you may be right in that the istream shifting=
 into a container is important enough to warrant a separate functionality. =
I don't like the separate function names though, and offer that the basic f=
unction could take a template template parameter which defaults to back_ins=
erter. A "overwriting" inserter would be used to handle your range case (wh=
ere you use stream_range). The naming is a later issue but insert is a bit =
odd. elements_of() reads better in context, I think:</div><div><br></div><d=
iv>cin &gt;&gt; elements_of(v); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &=
nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Uses back_inserter as expecte=
d as default</div><div>cin &gt;&gt; elements_of&lt;front_inserter&gt;(v)<wb=
r>; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &=
nbsp;// Puts the elements first (in reverse order???)</div><div>cin &gt;&gt=
; elements_of&lt;inserter&gt;(v, next(v, 10)); &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp;// Puts the elements at index 10 (not in reverse order I assum=
e)</div><div>cin &gt;&gt; elements_of&lt;replacer&gt;(v, next(v, 10), next(=
v, 20)); // Replaces up to 10 elements of v. I think y proper overloading a=
nd maybe enable_if we can get rid of the redundant 'v' parameter here.</div=
><div><br></div><div>The idea of giving the proxy object returned by elemen=
ts_of a name and allow it to return the count is still valid as you indicat=
ed.</div><div><br></div><div>What remains is how to convey the insert posit=
ion for the "center insert" case and a possibility to send in a subrange of=
 a container to the "replacer" version. I propose to solve this using an ad=
ditional parameter pack forwarded to the inserter:</div><div><br></div><div=
>template&lt;template&lt;typename&gt; inserter, typename C, typename... Ps&=
gt; _unspecified_ element_of(C&amp; container, Ps&amp;&amp; ps) { return _u=
nspecified_&lt;inserter&lt;<wbr>typename C::value_type&gt;&gt;(inserter&lt;=
<wbr>typename C::value_type&gt;(C, ps...)); }</div><div><br></div><div><br>=
</div><div><div><br>Den m=C3=A5ndagen den 21:e juli 2014 kl. 01:44:38 UTC+2=
 skrev Mark A. Gibbs:<blockquote class=3D"gmail_quote" style=3D"margin:0;ma=
rgin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"lt=
r">On Sunday, 20 July 2014 14:58:45 UTC-4, Bengt Gustafsson  wrote:<blockqu=
ote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1=
px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>I think these two sug=
gestions should be=20
synchronized so that we get one functionaliy which can do both input and
 output between a string or stream and a &nbsp;container or range, and whic=
h=20
includes the splitting options offered by the split proposal.</div></div></=
blockquote><div><br>When I first read your suggestions, I thought that woul=
d be the perfect solution - not only would it eliminate the need for anothe=
r standard library name (I've been using "stream_range", which is clunky), =
it would create a single interface to do what seem to be similar jobs.<br><=
br>But the more I thought about it, the more I realized this would be a mis=
take. While the operations of join() and stream_range() seem superficially =
similar from a really distant perspective, there are enough subtle differen=
ces in the practical application and the ways these functions will probably=
 be used to make it impossible to use the same function for both jobs. Also=
, it would essentially just be reinventing the same problem that inspired m=
e to make the suggestion in the first place - it shouldn't be necessary to =
include the algorithms library to do basic I/O, and streaming a range shoul=
d be basic I/O (put yourself in the shoes of a beginner who has just writte=
n a simple C++ program that includes the vector header and the iostream hea=
der, then does nothing in main but create a vector v and try to write it wi=
th "std::cout &lt;&lt; std::stream_range(v);"... only to discover the progr=
am won't compile because you're missing the "algorithm" header, leaving you=
 scratching your head because you didn't really use any algorithms: you jus=
t tried to print a vector).<br><br>But there are more dangerous problems, t=
oo. For example, if we merged this functionality into join(), then join() w=
ould have to return a proxy object that references the source range rather =
than a string. This may seem fine, especially if the proxy object has an im=
plicit conversion to string, but:<br><br><div style=3D"background-color:rgb=
(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-width=
:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">class</spa=
n><span style=3D"color:#000"> team<br></span><span style=3D"color:#660">{</=
span><span style=3D"color:#000"><br></span><span style=3D"color:#008">publi=
c</span><span style=3D"color:#660">:</span><span style=3D"color:#000"><br>&=
nbsp; </span><span style=3D"color:#008">void</span><span style=3D"color:#00=
0"> add_player</span><span style=3D"color:#660">(</span><span style=3D"colo=
r:#008">string</span><span style=3D"color:#000"> s</span><span style=3D"col=
or:#660">)</span><span style=3D"color:#000"> </span><span style=3D"color:#6=
60">{</span><span style=3D"color:#000"> players_</span><span style=3D"color=
:#660">.</span><span style=3D"color:#000">push_back</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">move</span><span style=3D"colo=
r:#660">(</span><span style=3D"color:#000">s</span><span style=3D"color:#66=
0">));</span><span style=3D"color:#000"> </span><span style=3D"color:#660">=
}</span><span style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#=
008">void</span><span style=3D"color:#000"> drop_player</span><span style=
=3D"color:#660">(</span><span style=3D"color:#008">string</span><span style=
=3D"color:#000"> </span><span style=3D"color:#008">const</span><span style=
=3D"color:#660">&amp;</span><span style=3D"color:#000"> s</span><span style=
=3D"color:#660">)</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#660">{</span><span style=3D"color:#000"> players_</span><span style=
=3D"color:#660">.</span><span style=3D"color:#000">erase</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">find</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">players_</span><span sty=
le=3D"color:#660">.</span><span style=3D"color:#008">b<wbr>egin</span><span=
 style=3D"color:#660">(),</span><span style=3D"color:#000"> players_</span>=
<span style=3D"color:#660">.</span><span style=3D"color:#008">end</span><sp=
an style=3D"color:#660">(),</span><span style=3D"color:#000"> s</span><span=
 style=3D"color:#660">));</span><span style=3D"color:#000"> </span><span st=
yle=3D"color:#660">}</span><span style=3D"color:#000"><br>&nbsp; <br>&nbsp;=
 </span><span style=3D"color:#008">auto</span><span style=3D"color:#000"> c=
urrent_roster</span><span style=3D"color:#660">()</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#008">const</span><span style=3D"color=
:#000"><br>&nbsp; </span><span style=3D"color:#660">{</span><span style=3D"=
color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#800">// If join(=
) returned a string - as currently spec'ed - no problems in this</span><spa=
n style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#800">=
// entire program. But if join() returns an adaptable proxy object with an<=
/span><span style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"co=
lor:#800">// implicit string conversion that lazy-evaluates....</span><span=
 style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#008">r=
eturn</span><span style=3D"color:#000"> join</span><span style=3D"color:#66=
0">(</span><span style=3D"color:#000">players_</span><span style=3D"color:#=
660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#080">=
", "</span><span style=3D"color:#660">);</span><span style=3D"color:#000"><=
br>&nbsp; </span><span style=3D"color:#660">}</span><span style=3D"color:#0=
00"><br>&nbsp; <br></span><span style=3D"color:#008">private</span><span st=
yle=3D"color:#660">:</span><span style=3D"color:#000"><br>&nbsp; vector</sp=
an><span style=3D"color:#080">&lt;string&gt;</span><span style=3D"color:#00=
0"> players_</span><span style=3D"color:#660">;</span><span style=3D"color:=
#000"><br></span><span style=3D"color:#660">};</span><span style=3D"color:#=
000"><br><br></span><span style=3D"color:#008">auto</span><span style=3D"co=
lor:#000"> t </span><span style=3D"color:#660">=3D</span><span style=3D"col=
or:#000"> team</span><span style=3D"color:#660">{};</span><span style=3D"co=
lor:#000"><br>t</span><span style=3D"color:#660">.</span><span style=3D"col=
or:#000">add_player</span><span style=3D"color:#660">(</span><span style=3D=
"color:#080">"Bruiser"</span><span style=3D"color:#660">);</span><span styl=
e=3D"color:#000"><br>t</span><span style=3D"color:#660">.</span><span style=
=3D"color:#000">add_player</span><span style=3D"color:#660">(</span><span s=
tyle=3D"color:#080">"T-bone"</span><span style=3D"color:#660">);</span><spa=
n style=3D"color:#000"><br><br></span><span style=3D"color:#800">// No prob=
lems yet...</span><span style=3D"color:#000"><br></span><span style=3D"colo=
r:#008">auto</span><span style=3D"color:#000"> s1 </span><span style=3D"col=
or:#660">=3D</span><span style=3D"color:#000"> std</span><span style=3D"col=
or:#660">::</span><span style=3D"color:#008">string</span><span style=3D"co=
lor:#660">{};</span><span style=3D"color:#000"><br>s1 </span><span style=3D=
"color:#660">=3D</span><span style=3D"color:#000"> t</span><span style=3D"c=
olor:#660">.</span><span style=3D"color:#000">current_roster</span><span st=
yle=3D"color:#660">();</span><span style=3D"color:#000"> </span><span style=
=3D"color:#800">// proxy object implicit string conv gives "Bruiser, T-bone=
"</span><span style=3D"color:#000"><br>cout </span><span style=3D"color:#66=
0">&lt;&lt;</span><span style=3D"color:#000"> t</span><span style=3D"color:=
#660">.</span><span style=3D"color:#000">current_roster</span><span style=
=3D"color:#660">();</span><span style=3D"color:#000"> </span><span style=3D=
"color:#800">// proxy object prints "Bruiser, T-bone"</span><span style=3D"=
color:#000"><br><br><br></span><span style=3D"color:#800">// Uh oh!</span><=
span style=3D"color:#000"><br></span><span style=3D"color:#008">auto</span>=
<span style=3D"color:#000"> team_before </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> t</span><span style=3D"color:#660">.<=
/span><span style=3D"color:#000">current_roster</span><span style=3D"color:=
#660">();</span><span style=3D"color:#000"> </span><span style=3D"color:#80=
0">// proxy object references internal vector</span><span style=3D"color:#0=
00"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbs=
p; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</s=
pan><span style=3D"color:#800">// (contains: "Bruiser", "T-bone")</span><sp=
an style=3D"color:#000"><br><br>t</span><span style=3D"color:#660">.</span>=
<span style=3D"color:#000">drop_player</span><span style=3D"color:#660">(</=
span><span style=3D"color:#080">"Bruiser"</span><span style=3D"color:#660">=
);</span><span style=3D"color:#000"><br>t</span><span style=3D"color:#660">=
..</span><span style=3D"color:#000">add_player</span><span style=3D"color:#6=
60">(</span><span style=3D"color:#080">"Stabby"</span><span style=3D"color:=
#660">);</span><span style=3D"color:#000"><br><br></span><span style=3D"col=
or:#800">// Proxy object team_before now references vector with "T-bone", "=
Stabby"!</span><span style=3D"color:#000"><br><br></span><span style=3D"col=
or:#008">auto</span><span style=3D"color:#000"> team_after </span><span sty=
le=3D"color:#660">=3D</span><span style=3D"color:#000"> t</span><span style=
=3D"color:#660">.</span><span style=3D"color:#000">current_roster</span><sp=
an style=3D"color:#660">();</span><span style=3D"color:#000"> </span><span =
style=3D"color:#800">// proxy object references internal vector</span><span=
 style=3D"color:#000"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp=
; &nbsp; </span><span style=3D"color:#800">// (contains: "T-bone", "Stabby"=
)</span><span style=3D"color:#000"><br><br>cout </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#080">"Team before trade: "</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> team_bef=
ore </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#=
000"> </span><span style=3D"color:#080">'\n'</span><span style=3D"color:#66=
0">;</span><span style=3D"color:#000"><br>cout </span><span style=3D"color:=
#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"colo=
r:#080">"Team after trade: &nbsp;"</span><span style=3D"color:#000"> </span=
><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> team=
_after </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#080">'\n'</span><span style=3D"color:=
#660">;</span><span style=3D"color:#000"><br></span><span style=3D"color:#8=
00">// Output is:</span><span style=3D"color:#000"><br></span><span style=
=3D"color:#800">// Team before trade: T-bone, Stabby</span><span style=3D"c=
olor:#000"><br></span><span style=3D"color:#800">// Team after trade: &nbsp=
;T-bone, Stabby</span></div></code></div><br>Try explaining that error to a=
 beginner.<br><br>What's happening here is that the proxy object that eithe=
r streams or "strings" has to hold a reference to the original range. It ca=
n't copy it (that would be expensive), and it can't know until it is used w=
hether it will be used to make a string or for streaming. Unless you explic=
itly cast the result of join() to a string (or assign it to a string), you'=
re getting the proxy object, which, with auto and return type deduction, me=
ans you may not be aware that you're trucking around a proxy object that pr=
obably holds a reference to the original range. If the original range goes =
out of scope before the proxy object (and the example above can be easily m=
odified to demonstrate that), bang. Even if it doesn't, you can get surpris=
ing results, as shown above.<br><br>Between this and the problem of which h=
eader to put join() in, I just can't see a way to resolve the two different=
 types of functionality down to a single function. Consider the following t=
wo statements:<br><br><div style=3D"background-color:rgb(250,250,250);borde=
r-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:brea=
k-word"><code><div><span style=3D"color:#000">cout </span><span style=3D"co=
lor:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"=
color:#080">"{ "</span><span style=3D"color:#000"> </span><span style=3D"co=
lor:#660">&lt;&lt;</span><span style=3D"color:#000"> join</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">v</span><span style=3D"c=
olor:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:=
#080">", "</span><span style=3D"color:#660">)</span><span style=3D"color:#0=
00"> </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:=
#000"> </span><span style=3D"color:#080">" }"</span><span style=3D"color:#6=
60">;</span><span style=3D"color:#000"><br>cout </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#080">"{ "</span><span style=3D"color:#000"> </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> stream_range</span><span =
style=3D"color:#660">(</span><span style=3D"color:#000">v</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#080">", "</span><span style=3D"color:#660">)</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"c=
olor:#000"> </span><span style=3D"color:#080">" }"</span><span style=3D"col=
or:#660">;</span></div></code></div><br>They both look the same, and they b=
oth give identical results... but they do it in very, very different ways u=
nder the hood (in this case, join() would probably be quite inefficient com=
pared to stream_range() - in non-streaming cases, the opposite would be tru=
e). It is not inconceivable that a programmer might want to insist on the b=
ehaviour of the first statement or the second - taking away the option of c=
hoosing what they want (or at least making it more difficult to do so) seem=
s counterproductive. And more importantly, they are both very different typ=
es of tasks. The former is to join the elements of the range into an object=
 that you can hold on to and pass around (a string, in this case), while th=
e latter is to coordinate output in a stream expression and is not intended=
 to create a new, independent object. Strings and streams are just too diff=
erent for there to be a single function to handle both. The apparent simila=
rities are just superficial.<br><br>Which is too bad - I would have liked t=
o use "join" (rather than "stream_range").<br>&nbsp;</div><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr">I'm sceptical to the idea of a inpu=
t function receiving into a range, as the typical use case is to not know t=
he length in advance, and it is very logical to a programmer to just state =
"push back the incoming things into this container, please".</div></blockqu=
ote><div><br>My intention is to ultimately have a family of functions for i=
nput - the only one I've done so far is the one that overwrites a range wit=
h input values.<br><br>I don't think it's that rare to want to read a known=
 number of values into a range, and there is currently no way to do it with=
out manually writing a loop. You can't use copy_n() with an istream iterato=
r, because it doesn't check for EOF (or any problems, really) - if the inpu=
t stream goes bad halfway through, you end up with your container half-full=
 of garbage (likely the last properly read value repeated). I don't think i=
t's that rare to have an object of fixed size and to expect to read exactly=
 that many values (for example, reading a 3d transformation matrix - it's a=
lways going to be 16 elements), or to have input that gives the number of i=
tems in a list before the list itself (that's a rather common file structur=
e, really).<br><br>Also, consider buffering. One of the ideas I'm toying wi=
th is to have the proxy object have a count() function, giving the number o=
f items successfully written/read (and maybe a reset() function to reset it=
 to 0). So suppose you have a huge dataset - you can read in 100 values at =
a time and work with them like this:<br><br><div style=3D"background-color:=
rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-wi=
dth:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">auto</s=
pan><span style=3D"color:#000"> buffer </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> std</span><span style=3D"color:#660">=
::</span><span style=3D"color:#000">array</span><span style=3D"color:#660">=
&lt;</span><span style=3D"color:#008">double</span><span style=3D"color:#66=
0">,</span><span style=3D"color:#000"> </span><span style=3D"color:#066">10=
0</span><span style=3D"color:#660">&gt;{};</span><span style=3D"color:#000"=
><br><br></span><span style=3D"color:#008">while</span><span style=3D"color=
:#000"> </span><span style=3D"color:#660">(</span><span style=3D"color:#008=
">in</span><span style=3D"color:#660">)</span><span style=3D"color:#000"><b=
r></span><span style=3D"color:#660">{</span><span style=3D"color:#000"><br>=
&nbsp; </span><span style=3D"color:#008">auto</span><span style=3D"color:#0=
00"> p </span><span style=3D"color:#660">=3D</span><span style=3D"color:#00=
0"> std</span><span style=3D"color:#660">::</span><span style=3D"color:#000=
">stream_range</span><span style=3D"color:#660">(</span><span style=3D"colo=
r:#000">buffer</span><span style=3D"color:#660">);</span><span style=3D"col=
or:#000"><br>&nbsp; </span><span style=3D"color:#008">in</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">&gt;&gt;</span><span sty=
le=3D"color:#000"> p</span><span style=3D"color:#660">;</span><span style=
=3D"color:#000"> </span><span style=3D"color:#800">// That's it for input! =
This will attempt to read 100 doubles, and</span><span style=3D"color:#000"=
><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style=3D"color:#=
800">// it will stop early and gracefully if it can't.</span><span style=3D=
"color:#000"><br>&nbsp; <br>&nbsp; </span><span style=3D"color:#008">if</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#660">(</span><s=
pan style=3D"color:#000">p</span><span style=3D"color:#660">.</span><span s=
tyle=3D"color:#000">count</span><span style=3D"color:#660">())</span><span =
style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#660">{</span><=
span style=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#00=
8">auto</span><span style=3D"color:#000"> working_range </span><span style=
=3D"color:#660">=3D</span><span style=3D"color:#000"> make_range</span><spa=
n style=3D"color:#660">(</span><span style=3D"color:#008">begin</span><span=
 style=3D"color:#660">(</span><span style=3D"color:#000">buffer</span><span=
 style=3D"color:#660">),</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#008">next</span><span style=3D"color:#660">(</span><span style=
=3D"color:#008">begin</span><span style=3D"color:#660">(</span><span style=
=3D"color:#000">buffer</span><span style=3D"color:#660">),</span><span styl=
e=3D"color:#000"> p</span><span style=3D"color:#660">.</span><span style=3D=
"color:#000">count</span><span style=3D"color:#660">()));</span><span style=
=3D"color:#000"><br>&nbsp; &nbsp; <br>&nbsp; &nbsp; </span><span style=3D"c=
olor:#800">// Now do your calculations with whatever was read in.</span><sp=
an style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#660">}</spa=
n><span style=3D"color:#000"><br>&nbsp; <br>&nbsp; </span><span style=3D"co=
lor:#800">// Or instead of the if block above, you can do:</span><span styl=
e=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#800">// auto worki=
ng_range =3D make_range(begin(buffer), next(begin(buffer), p.count()));</sp=
an><span style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#800">=
// if (!empty(working_range)) { ... }</span><span style=3D"color:#000"><br>=
</span><span style=3D"color:#660">}</span></div></code></div><br>While read=
ing into an expanding range should be an option, I don't think it should be=
 the only option. Expanding is expensive and not fail-safe, so in cases whe=
re you can know the number of items to read before reading, you should alwa=
ys prefer to at least reserve() the space, if not straight-up create the re=
ceiving range already properly sized then read into it.<br><br>Once I work =
out the wrinkles, I am going to add 3 more functions, which I am currently =
calling stream_range_back_insert(), stream_range_front_insert(), and stream=
_range_insert(), but which could just as well be called back_insert(), fron=
t_insert(), and insert(), because this is the only possible context where t=
hey can take 1, 1, and 2 arguments respectively. They would handle the case=
 where you don't know the number of elements beforehand:<br><br><div style=
=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-=
style:solid;border-width:1px;word-wrap:break-word"><code><div><span style=
=3D"color:#000">std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#000">cin </span><span style=3D"color:#660">&gt;&gt;</span><span =
style=3D"color:#000"> std</span><span style=3D"color:#660">::</span><span s=
tyle=3D"color:#000">stream_range</span><span style=3D"color:#660">(</span><=
span style=3D"color:#000">v</span><span style=3D"color:#660">);</span><span=
 style=3D"color:#000"> </span><span style=3D"color:#800">// Replaces all el=
ements of v with input.</span><span style=3D"color:#000"><br><br>std</span>=
<span style=3D"color:#660">::</span><span style=3D"color:#000">cin </span><=
span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> std</s=
pan><span style=3D"color:#660">::</span><span style=3D"color:#000">back_ins=
ert</span><span style=3D"color:#660">(</span><span style=3D"color:#000">v</=
span><span style=3D"color:#660">);</span><span style=3D"color:#000"> </span=
><span style=3D"color:#800">// Adds elements using v.push_back(x).</span><s=
pan style=3D"color:#000"><br>std</span><span style=3D"color:#660">::</span>=
<span style=3D"color:#000">cin </span><span style=3D"color:#660">&gt;&gt;</=
span><span style=3D"color:#000"> std</span><span style=3D"color:#660">::</s=
pan><span style=3D"color:#000">front_insert</span><span style=3D"color:#660=
">(</span><span style=3D"color:#000">v</span><span style=3D"color:#660">);<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#800">// Adds=
 elements using v.push_front(x).</span><span style=3D"color:#000"><br>std</=
span><span style=3D"color:#660">::</span><span style=3D"color:#000">cin </s=
pan><span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> s=
td</span><span style=3D"color:#660">::</span><span style=3D"color:#000">ins=
ert</span><span style=3D"color:#660">(</span><span style=3D"color:#000">v</=
span><span style=3D"color:#660">,</span><span style=3D"color:#000"> i</span=
><span style=3D"color:#660">);</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#800">// Adds elements using v.insert(i, x).</span><span =
style=3D"color:#000"><br><br></span><span style=3D"color:#800">// In all ca=
ses above, input stops when bool(std::cin) is false.</span><span style=3D"c=
olor:#000"><br></span><span style=3D"color:#800">// If you want to know how=
 many items were actually successfully read (only</span><span style=3D"colo=
r:#000"><br></span><span style=3D"color:#800">// relevant in the first case=
, really), you should do:</span><span style=3D"color:#000"><br></span><span=
 style=3D"color:#800">// auto p =3D std::stream_range(v); // or whichever f=
unction you wish to use</span><span style=3D"color:#000"><br></span><span s=
tyle=3D"color:#800">// std::cin &gt;&gt; p;</span><span style=3D"color:#000=
"><br></span><span style=3D"color:#800">// And the number of successfully r=
ead items is in p.count().</span></div></code></div><br>At the moment I'm n=
ot concerned with the names - that can be dealt with later. (For example, m=
aybe "overwrite" could be used for the first case above, and "output" or "w=
rite_all" could be used for the ostream version.) I'm more concerned with m=
aking this as flexible as possible, while keeping it easy to use. One of th=
e things I'm most concerned with is adding means to detect if and - more im=
portantly - when I/O failed. That's something that no current method (using=
 stream iterators or algorithms like copy) does, and unfortunately, split()=
 doesn't seem equipped to do it either (along with its other issues, like b=
eing in the algorithms library).<br>&nbsp;</div><blockquote class=3D"gmail_=
quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddi=
ng-left:1ex"><div dir=3D"ltr"> <div>It could be worth investigating if join=
() should be elaborated with some more options like split(), for instance t=
o handle a limited line length or n-items per row printout, as well as mayb=
e fixed width comlumns with space fill and things like that.</div></div></b=
lockquote><div><br>That seems like going way beyond the mandate of a simple=
 range streaming facility. Those things might be useful (though I'm not par=
ticularly sure that standardizing a pretty-printing text output library is =
worth the effort in an age of graphical UIs), but the sheer number of permu=
tations of reasonable options is just too much to even begin to consider fo=
r a basic function.<br><br>If this is worth investigating (I'm not convince=
d), it should be investigated as an entirely separate library, because it i=
sn't really related to ranges or streaming ranges.<br>&nbsp;</div><blockquo=
te class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>An alternative is to l=
et split() without the string parameter return a helper object with an over=
loaded &gt;&gt; from istream, which does the work:</div></div></blockquote>=
<div><br>As far as I know, split() is defined as taking a source string(vie=
w) and a delimiter - it doesn't take the output range, it returns a proxy o=
bject made up of string_views into the original string. Have there been cha=
nges since N3593? Because if not, with that interface, there's really no wa=
y to handle both "regular" splitting, and "splitting" from an input stream.=
</div></div></blockquote></div></div></div></blockquote></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_333_1185061530.1406036427324--

.


Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Wed, 23 Jul 2014 16:00:48 -0700 (PDT)
Raw View
------=_Part_97_1425657621.1406156448524
Content-Type: text/plain; charset=UTF-8

On Tuesday, 22 July 2014 05:01:32 UTC-4, Bengt Gustafsson wrote:
>
> A proposal to define an "operator auto" so that a class with "lazy"
> semantics can be instructed to convert to a certain type (in this case
> string) when "converted to auto", such as in your function current_roster.
> I think is a typical usecase for that functionality.
>

Ah, I'd forgotten about that proposal. I'm wary of it, though, because it
seems too brittle to me. I can just see someone doing:

using team_roster_type = decltype(t.current_roster()); // or result_of<>

team_roster_type team_before = t.current_roster();
// ...

And they might end up with the same problem. (And I say "might" because I'm
still not clear exactly on how this auto evaluating is supposed to work.)

Regardless, even if you solve the problem of accidentally trucking around
proxy objects, there are still several problems with merging join() and
range streaming (which I'll mention below).


> I think you got things messed up in your comparison of join() and
> stream_range() in the ostream shift example: The sole reason for having a
> proxy object and getting the (now solved) problem with the hidden proxy
> object was that this proxy object can be the rhs of a << operator without
> the interveaning conversion to string! Now you claim the performance
> penalty of join is still there. Maybe this was under the assumption that a
> proxy object would be unacceptable and thus join just returning string.
>

Yes, I am working with the assumption that join() does what it's currently
spec'ed to do, and stream_range() does what I'm proposing. In that case,
the following two statements produce identical results (in some cases!) in
the output stream sequence (for most output streams!) but they do it in
very different ways:

auto v = { 1, 2, 3, 4 };
out << join(v, "+") << '\n';
out << stream_range(v, "+") << '\n';

The point I was making was that *both* of these two behaviours are useful,
and *both* should be possible. Because there are situations where you would
specifically want one or the other. I'll give two examples.

Under normal circumstances, you would prefer the second statement (with
stream_range) - it will be more efficient than joining the range into a
string then writing the string. But if you have a logging stream, you might
set it to have a unit buffer. If the stream has a unit buffer, the equation
is completely different - the first statement will probably be
significantly faster than the second. More importantly, there is no way to
mechanically determine which way would be better - so we can't even get
around this by calling it a QOI issue and saying implementations can check
for whether there's a unit buffer - because which way is "right" depends on
design factors. In some cases a programmer might *want* each element of the
stream written individually and damn the flushing costs... in other cases a
programmer might prefer building the string then writing the whole thing as
one unit write. It would depend on high-level design considerations the
language and implementation can't be privy too.

Here's another tricky question - what should this code do?:

out.setf(ios_base::hex, ios_base::basefield);
out.setf(ios_base::showbase);

auto v = { 1, 2, 3, 4 };
out << join(v, "+") << '\n';
out << stream_range(v, "+") << '\n';

Using the current proposals, it does this:

1+2+3+4
0x1+0x2+0x3+0x4

Which is "correct"? My answer is: both. It depends on what you want. And
note that this is something that the implicit proxy auto conversion
actually makes *worse*, because it would mean that this:

auto s = join(v, "+");
out << s;
// "1+2+3+4";

and this:

out << join(v, "+");
// "0x1+0x2+0x3+0x4"

produce different results.

For a less esoteric case, consider when you're trying to align data in
columns 10 characters wide:

auto v = { 1, 2, 3 };
out.fill('_');
out << setw(10) << join(v, "+") << '\n';
out << setw(10) << stream_range(v, "+") << '\n';

Under the current proposals, the results are:

_____1+2+3
_________1+_________2+_________3

Again, which is "correct"? My answer is that both are correct, and there
are situations where you would want either behaviour. Neither behaviour is
particularly "weird". Sometimes you want to treat the whole range as a
single "thing" (which is why they named the operation "join" - multiple
things that are joined become one thing), sometimes you want to consider
each element individually. This is why I say that "join" is an entirely
different type of operation to streaming a range. The fact that it produces
identical results *in some situations* is a red herring.

Incidentally, it's not in the documentation yet, but the implementation on
github already does this behaviour. Check the output.cpp test, and look for
the Formatting tests. With the current implementation you can write (though
I haven't tested this):

auto data = make_array(
  make_array( 1.2130, -3.5856,  8.3570,  9.3582),
  make_array( 7.3758, -6.3573,  1.0395,  2.0118),
  make_array(-4.4782,  2.2353,  8.0123,  5.3253)
);

cout << "   v1   |   v2   |   v3   |   v4\n";
cout << "--------+--------+--------+--------\n";

cout.precision(3);
cout.fill(' ');
cout.setf(ios_base::showpos);
cout.setf(ios_base::internal, ios_base::adjustfield);

for_each(begin(data), end(data), [](auto const& row)
  { cout << ' ' << setw(6) << stream_range(row, " | ") << '\n'; });

And get:

   v1   |   v2   |   v3   |   v4
--------+--------+--------+--------
 + 1.21 | - 3.59 | + 8.36 | + 9.36
 + 7.38 | - 6.36 | + 1.04 | + 2.01
 - 4.48 | + 2.24 | + 8.01 | + 5.33

Which ain't bad, I think.

An implicit auto conversion would also torpedo the idea of being able to
detect errors. Under the design I'm working toward, you can figure out
(almost) exactly where and what went wrong with output like this:

auto p = stream_range(v, ", "); // (1)
if (!(out << p)
{
  // What went wrong? Well:
  // if (out.bad()) there was an unrecoverable I/O error
  // if (out.fail()) there was a recoverable I/O error
  // p.count() will tell you exactly which element in the range v the error
  // occurred at.
}

If there's an automatic conversion to string at (1), then the possibility
of detecting how many elements were written before the error is gone, and
we're back to the bad old days of using copy() and stream iterators that
give virtually no help when there's an error.

The bottom line is that "join" is an entirely different "type" of operation
than streaming a range. "join" is basically a "reduce" (or you could do it
with std::accumulate()) operation with a function that stringifies and
concatenates... that's not even in the same conceptual universe as a loop
that prints elements of a range individually (with optional delimiter),
which is what range streaming is about. "join", for example, doesn't have
to worry about I/O failure, just running out of memory... the opposite is
true for range streaming: I/O failure is a major concern, but memory
allocation (usually) doesn't happen at all (obviously it does with a string
stream). Even if it were possible to somehow overload the name "join" to do
both jobs, I would still be against it, because range streaming is actually
*not* "joining" anything - the label would be incorrect for the job. That
they produce similar results in some cases is actually misleading. They do
very different jobs, and the differences cannot be smoothed out with snazzy
tricks like implicit auto conversions or brushing it off as a QOI problem -
choosing between the different behaviours is a design decision, not an
implementation one.


> I don't see the problem with the algorithm header as any other header
> using it would of course include it. That is, unless you are worried about
> compile times.
>

I'm actually more worried about modules and module dependencies.

But even if you're just thinking headers, you do *not* want the IOstreams
library including the Algorithms library. And you do not want the
Algorithms library including the IOstreams header. That means it becomes
the problem of the programmer to decide whether it's worth including both.
Frankly, if it were me, I wouldn't bother - if I had a file that didn't
need the algorithms library at all except for range streaming... i'd just
write a for loop (as i do now, not even using for_each()) rather than
dumping the entire algorithms library into my file... which is *exactly*
the kind of thing we'd want to avoid.

Put another way, suppose I had a header file that had a class that looked
something like this:

#ifndef include_guard
#define include_guard

#include <iosfwd>
#include <vector>

namespace ns {

template <typename T>
class something
{
  // stuff
  std::vector<T> data_;

  template <typename T, typename CharT, typename Traits>
  friend auto operator<<(std::basic_ostream<CharT, Traits>&, something<T>
const&) ->
    std::basic_ostream<CharT, Traits >&;
};

template <typename T, typename CharT, typename Traits>
auto operator<<(std::basic_ostream<CharT, Traits>& out, something<T> const&
s) ->
  std::basic_ostream<CharT, Traits >&;
{
  for (auto const& i : s)
    out << s << ' ';

  return out;
}

} // namespace ns

#endif // include_guard

That's a pretty plausible header for a pretty realistic class type, with
minimal dependencies for fast compiling in huge projects.

Now I want to upgrade this to use range streaming, to get multiple
benefits: simplicity, safety, the ability to add delimiters, and proper
handling of error conditions. If range streaming gets forward-declared in
<iosfwd> and actually defined in <ostream> and <istream> (for output and
input versions respectively) as I would hope, then the only change I would
have to make is replacing the body of the inserter function with "return
out << std::stream_range(s, ',');". But if it ends up in <algorithm> (as
join() or whatever), then now i have to include the *entire* algorithms
library... for one measly function. That's just ridiculous.

Here's another way to look at it. Suppose I have a custom replacement
algorithms library - <my_algorthims> rather than <algorithms>, or maybe
just a link in the file system so <algorithm> points to the new library -
that replaces the standard algorithms library... maybe it has neat
parallelization functionality, or maybe it has extra debugging features for
the testing phase. If I am forced to include <algorithm> *just* to get
convenient streaming for ranges in types like the one above, then the
decision of which algorithm library to include will have to be made in that
header (either that or it will have to effectively replicate the
functionality of range streaming)... rather than at places where algorithms
are *actually* used... and there's no good argument for why this should be
okay.

Currently, the library as I've written it depends only on <iosfwd> and
<utility>, and it uses the latter *only* for forward(), which means that
the *entire* library can be entirely contained within IOStreams with no
other dependencies. And i haven't sat down and worked it out yet (because
i'm still adding functionality), but i believe that it *might* be possible
that the five functions i've mentioned - stream_range(output), overwrite,
back_insert, front_insert, and insert - can be forward declared in
<iosfwd>, then stream_range(output) can be implemented in <ostream> and the
other four in <istream> (depends on whether I can implement the front/back
inserter stuff without needing the range library or type traits or
whatever). Or, at the worst case, it can all be in <iomanip>. There's just
no reason to bring <algorithm> - which is a *very* heavyweight header -
into the mix.


> But you may be right in that the istream shifting into a container is
> important enough to warrant a separate functionality. I don't like the
> separate function names though, and offer that the basic function could
> take a template template parameter which defaults to back_inserter.
>

Eh, that's ultimately a naming issue, which is a low priority for me. I
want to figure out *what* it should do... then *how* it should do it... and
only *then*, once all that is dealt with, worry about the name to slap on
it.

But for the record, this is supposed to be trivial, basic functionality -
the kind of stuff beginners should learn in the first or second class on
C++. Those look a little verbose and syntactically overwrought for
something a beginner might want to use. I mean, look at the comparison:

cin >> elements_of(v); // 22 chars
cin >> elements_of<front_inserter>(v); // 38 chars
cin >> elements_of<inserter>(v, next(begin(v), 10)); // 52 chars
cin >> elements_of<replacer>(v, next(begin(v), 10), next(begin(v), 20)); //
72 chars

// versus...

cin >> back_insert(v); // 22 chars (same)
cin >> front_insert(v); // 23 chars (65% shorter)
cin >> insert(v, next(begin(v), 10)); // 37 chars (40% shorter)
cin >> overwrite(make_range(next(begin(v), 10), next(begin(v), 20)); // 68
chars (6% shorter)
// Or possibly
cin >> replace(make_range(next(begin(v), 10), next(begin(v), 20)); // 66
chars (9% shorter)

And that's *without* all the "std::"s.

Verbosity aside, I don't see how "elements_of" is clearer than "replace" or
"overwrite" when what you're *actually doing* is replacing or overwriting
the contents of a range. And if "elements_of" is supposed to back insert...
well, then let me tell you exactly what will happen. Thousands of C++
teachers and help sites are going to be flooded with questions about why
this doesn't work:

int data[24];
cin >> elements_of(data);

(And if you object to the naked array, replace it with std::array. Or
std::forward_list, for that matter.)

Frankly, all other issues aside, making "back insert" the default behaviour
would be horribly wrong-headed. One of the first things C++ beginners learn
about input is that when they do:

type x;
cin >> x;

that a value with the type of "type" is read in from cin and it *replaces*
the value of x. *Not* "extends the value of x". *Not* "adds to the value of
x"... *replaces* (or overwrites) the value of x. You wouldn't be making
things easier for beginners, you would be creating yet another "exception
to the rule" that they'd have to memorize. The behaviour of stream input to
single values is to overwrite/replace - you may think that's silly, you may
not like it, but that's what it is. Therefore the behaviour of stream input
to ranges should be the same... unless otherwise specified.

So all else aside, the default behaviour for elements_of() should be the
replacing option, not back inserting.

Now, from my experience teaching C++, I have discovered that when beginners
read code, they tend to try and form vaguely English sentences from the
code by reading identifiers, describing operators, and dropping
punctuation. When that actually works and correctly describes what is
happening, they grasp things easily. When it doesn't, they struggle. So
consider these two expressions:

cin >> overwrite(values);
cin >> elements_of(values);

A beginner will probably read these as:

"cin... input into... overwite... values"    -> "input from cin,
overwriting 'values'"
"cin... input into... elements of... values" -> "input from cin into the
elements of 'values'"

Not bad. In both cases the default way a beginner will read the code gives
the correct interpretation. So far so good.

cin >> front_insert(values);
cin >> elements_of<front_inserter>(values);

Which will probably be read as:

"cin... input into... front insert... values"                  -> "input
from cin and front insert into 'values'"
"cin... input into... elements of... front inserter... values" -> "what?
elements of front inserter?
                                                                   so
insert input from cin in front of each element of 'values'?"

You're assuming "elements_of<front_inserter>(values)" will be read as
"elements of { front inserter values }" and not "{ elements of front
inserter } values". Let me assure you, assumptions like that will only lead
to grief when you're trying to teach beginners.

Even more infuriating for me as a teacher will be trying to explain how
these things work. Imagine you're only three or four classes in - you've
covered variables (they understand vector<T> as "a variably-sized bunch of
T values", but nothing more), basic functions, references, simple classes
(basically POD strucs), and now it's time for input. You've explained that:

int n;
cin >> n;

really just translates into something that looks like:

auto operator>>(istream& in, int& i) -> istream&
{
  // magic to read characters from in and convert them to an int value,
  // which gets put in i.
}

int n;
operator>>(cin, n);

and they grasp this much. (Obviously you wouldn't mention the myriad
complications involved in *really* writing that function (sometimes I've
"demonstrated" the function using getline() and atoi() - nowadays i suppose
i'd use stoi()). It's only class 3 or 4 after all. But at least this much
is enough for the beginners to grasp, and even riff on, to a limited
degree.) Now it's time to read ranges.

I can show a beginner:

auto values = vector<int>{ 1, 2, 3, 4 };
cin >> overwrite(values);
cin >> back_insert(values);
cin >> insert(values, begin(values) + 3);

and not only will they understand what is happening... *they will be able
to replicate it* with only the most basic understanding of C++. I can
explain to them that overwrite() returns an object of a special type, and
then demonstrate it like this:

struct my_overwrite_type
{
  vector<int>& v;
};

auto operator>>(istream& in, my_overwrite_type owt) -> istream&
{
  for (auto& i : owt.v)
    in >> i;
}

auto my_overwrite(vector<int>& v)
{
  return my_overwrite_type{v};
}

cin >> my_overwrite(values);

That is all done with only the most basic and trivial C++ constructs. After
demonstrating and explaining that, I can then send them off with a
challenge to duplicate back_insert(), and (for bonus points) insert()...
*and they can do it* (assuming i've told them about vector::push_back() and
vector::insert()). In fact, after we've covered basic template classes and
functions, I can let them have at it again, this time writing
my_overwrite() and my_back_insert() to take *any* type of range. Obviously
their code won't be able to perfectly replace the actual overwrite() and
back_insert() until they've covered quite a bit more... but that's a hell
of a lot of ground they can understand. *That* is what a facility intended
for use by beginners should be like - something they can understand, even
if only in broad terms.

Now, let's try it with elements_of(). I show them this:

auto values = vector<int>{ 1, 2, 3, 4 };
cin >> elements_of(values);
cin >> elements_of<back_inserter>(values);
cin >> elements_of<inserter>(values, begin(values) + 3);

How on earth would I explain how *these* work to beginners? Understanding
what's going on requires not just templates, but specialization
(technically, *partial* specialization) and overloading template functions *at
least* - not to mention the template template structure you described.
Hell, I'm a very experienced C++ programmer, and *I* am balking at
implementing this.

And for what do we need all this syntactic chicanery? What do we gain? The
declarations just get longer and unnecessarily verbose (is "back_insert(v)"
really less clear than "elements_of<back_inserter>(v)")? You can't make a
single elements_of<T>() with T being a "traits" type that changes the
behaviour, because the different functions have different signatures, so
now you're into the realm of variadic template functions (at least). Is it
really necessary to have a single range I/O function that allows you to
plug in behaviours? Why? Is there really any demand for anything beyond
simply overwriting and inserting at the front, back, or somewhere in the
middle? (And in the freakishly rare case where someone wants to do
something different, wouldn't a range adaptor be a better option than a
custom insert function? It would then be applicable to range-based
algorithms, too.) And you're not really making less new identifiers in the
std namespace, because back_inserter, front_inserter, and inserter already
exist as function names. You'd need new names for all of those, *plus*
elements_of. If you want to keep those names, I don't think your proposed
syntax is even possible (and if it is, it seems likely to be problematic
due to clashes with the existing functions).

For now, I'm focusing on figuring out the desired behaviour of these
facilities - the current names are just provisional (I don't really like
"stream_range", for example), and I was intending to put that off until
after I'd actually had a paper to submit. If you can actually make the
element_of syntax compile (I'd say don't bother worrying about the details
of the behaviour, such as formatting and error handling, just make it work
in the most simple cases, just to show the syntax works), and explain why
it would be better, I would appreciate that.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_97_1425657621.1406156448524
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tuesday, 22 July 2014 05:01:32 UTC-4, Bengt Gustafsson =
 wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">A prop=
osal to define an "operator auto" so that a class with "lazy" semantics can=
 be instructed to convert to a certain type (in this case string) when "con=
verted to auto", such as in your function current_roster. I think is a typi=
cal usecase for that functionality.</div></blockquote><div><br>Ah, I'd forg=
otten about that proposal. I'm wary of it, though, because it seems too bri=
ttle to me. I can just see someone doing:<br><br><div class=3D"prettyprint"=
 style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187,=
 187); border-style: solid; border-width: 1px; word-wrap: break-word;"><cod=
e class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color:=
 #008;" class=3D"styled-by-prettify">using</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> team_roster_type </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">decltype</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">t</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">cur=
rent_roster</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>());</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">// or result_o=
f&lt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br><br>team_roster_type team_before </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> t</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">current_roster</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">();</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br></span><span style=3D"color: #800;" class=3D"styled-by-prettify">// ...<=
/span></div></code></div><br>And they might end up with the same problem. (=
And I say "might" because I'm still not clear exactly on how this auto eval=
uating is supposed to work.)<br><br>Regardless, even if you solve the probl=
em of accidentally trucking around proxy objects, there are still several p=
roblems with merging join() and range streaming (which I'll mention below).=
<br>&nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"lt=
r">I think you got things messed up in your comparison of join() and stream=
_range() in the ostream shift example: The sole reason for having a proxy o=
bject and getting the (now solved) problem with the hidden proxy object was=
 that this proxy object can be the rhs of a &lt;&lt; operator without the i=
nterveaning conversion to string! Now you claim the performance penalty of =
join is still there. Maybe this was under the assumption that a proxy objec=
t would be unacceptable and thus join just returning string.</div></blockqu=
ote><div><br>Yes, I am working with the assumption that join() does what it=
's currently spec'ed to do, and stream_range() does what I'm proposing. In =
that case, the following two statements produce identical results (in some =
cases!) in the output stream sequence (for most output streams!) but they d=
o it in very different ways:<br><br><div class=3D"prettyprint" style=3D"bac=
kground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border=
-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"pr=
ettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=
=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> v </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #066;" class=3D"styled-by-prettify">1</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" clas=
s=3D"styled-by-prettify">2</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">3<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">4</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">out</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> jo=
in</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;=
" class=3D"styled-by-prettify">"+"</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">'\n'<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">out</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> stream_range</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">"+=
"</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #080;" class=3D"styled-by-prettify">'\n'</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">;</span></div></code></div><br>The point I =
was making was that <i>both</i> of these two behaviours are useful, and <i>=
both</i> should be possible. Because there are situations where you would s=
pecifically want one or the other. I'll give two examples.<br><br>Under nor=
mal circumstances, you would prefer the second statement (with stream_range=
) - it will be more efficient than joining the range into a string then wri=
ting the string. But if you have a logging stream, you might set it to have=
 a unit buffer. If the stream has a unit buffer, the equation is completely=
 different - the first statement will probably be significantly faster than=
 the second. More importantly, there is no way to mechanically determine wh=
ich way would be better - so we can't even get around this by calling it a =
QOI issue and saying implementations can check for whether there's a unit b=
uffer - because which way is "right" depends on design factors. In some cas=
es a programmer might *want* each element of the stream written individuall=
y and damn the flushing costs... in other cases a programmer might prefer b=
uilding the string then writing the whole thing as one unit write. It would=
 depend on high-level design considerations the language and implementation=
 can't be privy too.<br><br>Here's another tricky question - what should th=
is code do?:<br><br><div class=3D"prettyprint" style=3D"background-color: r=
gb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; b=
order-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div =
class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">out</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">setf</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify">ios_base</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">hex</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> ios_base</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">basefield</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">out</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">setf</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">ios_base</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">showbase</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> v </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #066;" class=3D"styled-by-prettify">1</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" =
class=3D"styled-by-prettify">2</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify=
">3</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #066;" class=3D"styled-by-prettify">4</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">out</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 join</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #0=
80;" class=3D"styled-by-prettify">"+"</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">'\=
n'</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">out</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> stream_range</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettif=
y">"+"</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #080;" class=3D"styled-by-prettify">'\n'</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">;</span></div></code></div><br>Using th=
e current proposals, it does this:<br><br><span style=3D"font-family: couri=
er new,monospace;">1+2+3+4<br>0x1+0x2+0x3+0x4</span><br><br>Which is "corre=
ct"? My answer is: both. It depends on what you want. And note that this is=
 something that the implicit proxy auto conversion actually makes <i>worse<=
/i>, because it would mean that this:<br><br><div class=3D"prettyprint" sty=
le=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187=
); border-style: solid; border-width: 1px; word-wrap: break-word;"><code cl=
ass=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> s </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> join</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">v=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #080;" class=3D"styled-by-prettify">"+"</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">out</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> s</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></spa=
n><span style=3D"color: #800;" class=3D"styled-by-prettify">// "1+2+3+4";</=
span></div></code></div><br>and this:<br><br><div class=3D"prettyprint" sty=
le=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187=
); border-style: solid; border-width: 1px; word-wrap: break-word;"><code cl=
ass=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">out</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> join</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #080;" class=3D"styled-by-prettify">"+"</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" c=
lass=3D"styled-by-prettify">// "0x1+0x2+0x3+0x4"</span></div></code></div><=
br>produce different results.<br><br>For a less esoteric case, consider whe=
n you're trying to align data in columns 10 characters wide:<br><br><div cl=
ass=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-c=
olor: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap=
: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> v </span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-p=
rettify">1</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #066;" class=3D"styled-by-prettify">2</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;"=
 class=3D"styled-by-prettify">3</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">ou=
t</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">fill</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #080;" class=3D"styled-by-prettify">'_'</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">out</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> setw</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(<=
/span><span style=3D"color: #066;" class=3D"styled-by-prettify">10</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> join</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">"+"=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #080;" class=3D"styled-by-prettify">'\n'</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">out</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 setw</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</sp=
an><span style=3D"color: #066;" class=3D"styled-by-prettify">10</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> stream_range</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">=
"+"</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #080;" class=3D"styled-by-prettify">'\n'</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">;</span></div></code></div><br>Under the c=
urrent proposals, the results are:<br><br><span style=3D"font-family: couri=
er new,monospace;">_____1+2+3<br>_________1+_________2+_________3</span><br=
><br>Again, which is "correct"? My answer is that both are correct, and the=
re are situations where you would want either behaviour. Neither behaviour =
is particularly "weird". Sometimes you want to treat the whole range as a s=
ingle "thing" (which is why they named the operation "join" - multiple thin=
gs that are joined become one thing), sometimes you want to consider each e=
lement individually. This is why I say that "join" is an entirely different=
 type of operation to streaming a range. The fact that it produces identica=
l results *in some situations* is a red herring.<br><br>Incidentally, it's =
not in the documentation yet, but the implementation on github already does=
 this behaviour. Check the output.cpp test, and look for the Formatting tes=
ts. With the current implementation you can write (though I haven't tested =
this):<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250=
, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-=
width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> da=
ta </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> make_array</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; make_array<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">1.2130</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">-</span><span style=3D"color: #066;" class=3D"styl=
ed-by-prettify">3.5856</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> &nbsp;</span><span style=3D"color: #066;" class=3D"styled-by-prettify">=
8.3570</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> &nbsp;</span=
><span style=3D"color: #066;" class=3D"styled-by-prettify">9.3582</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">),</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; make_array</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #066;" class=3D"styled-by-prettify">7.3758</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">-</span><span style=3D"color: #066;" class=3D"styled-by-p=
rettify">6.3573</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> &nb=
sp;</span><span style=3D"color: #066;" class=3D"styled-by-prettify">1.0395<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> &nbsp;</span><span =
style=3D"color: #066;" class=3D"styled-by-prettify">2.0118</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">),</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br>&nbsp; make_array</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(-</span><span style=3D"=
color: #066;" class=3D"styled-by-prettify">4.4782</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> &nbsp;</span><span style=3D"color: #066;" cl=
ass=3D"styled-by-prettify">2.2353</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> &nbsp;</span><span style=3D"color: #066;" class=3D"styled-b=
y-prettify">8.0123</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
&nbsp;</span><span style=3D"color: #066;" class=3D"styled-by-prettify">5.32=
53</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br><br>cout </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #080;" class=3D"styled-by-prettify">" &nbsp; v1 &nbsp; | &nbsp; v2 &nbsp;=
 | &nbsp; v3 &nbsp; | &nbsp; v4\n"</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br>cout </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettif=
y">"--------+--------+--------+--------\n"</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br><br>cout</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">precision</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">(</span><span style=3D"color: #066;" class=3D"styled-by-pre=
ttify">3</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>cout</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">fill</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #080;" class=3D"styled-by-prettify">' '</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>cout</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">setf</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
ios_base</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">showpos</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br>cout</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">setf</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">ios_base</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">::</span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">internal</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> ios_base</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">ad=
justfield</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br>f=
or_each</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">begin</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">data</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">),</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">end</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">data</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">),</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">[](</span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">const</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> row</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br>&nbsp; </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> cout </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">' '</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> setw</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #=
066;" class=3D"styled-by-prettify">6</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> stream_range</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
row</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #080;" class=3D"styled-by-prettify">" | "</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=3D"st=
yled-by-prettify">'\n'</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">});</s=
pan></div></code></div><br>And get:<br><br><span style=3D"font-family: cour=
ier new,monospace;">&nbsp;&nbsp; v1&nbsp;&nbsp; |&nbsp;&nbsp; v2&nbsp;&nbsp=
; |&nbsp;&nbsp; v3&nbsp;&nbsp; |&nbsp;&nbsp; v4<br>--------+--------+------=
--+--------<br>&nbsp;+ 1.21 | - 3.59 | + 8.36 | + 9.36<br>&nbsp;+ 7.38 | - =
6.36 | + 1.04 | + 2.01<br>&nbsp;- 4.48 | + 2.24 | + 8.01 | + 5.33</span><br=
><br>Which ain't bad, I think.<br><br>An implicit auto conversion would als=
o torpedo the idea of being able to detect errors. Under the design I'm wor=
king toward, you can figure out (almost) exactly where and what went wrong =
with output like this:<br><br><div class=3D"prettyprint" style=3D"backgroun=
d-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style=
: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"prettypr=
int"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> p </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> s=
tream_range</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">v</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #080;" class=3D"styled-by-prettify">", "</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D"sty=
led-by-prettify">// (1)</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">if</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(!(</span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">out</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> p</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>&nbsp; </span><span style=3D"color: #800;" class=3D"styled-by-=
prettify">// What went wrong? Well:</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #800;" cla=
ss=3D"styled-by-prettify">// if (out.bad()) there was an unrecoverable I/O =
error</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&=
nbsp; </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// i=
f (out.fail()) there was a recoverable I/O error</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"colo=
r: #800;" class=3D"styled-by-prettify">// p.count() will tell you exactly w=
hich element in the range v the error</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #800;" c=
lass=3D"styled-by-prettify">// occurred at.</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">}</span></div></code></div><br>If there's an aut=
omatic conversion to string at (1), then the possibility of detecting how m=
any elements were written before the error is gone, and we're back to the b=
ad old days of using copy() and stream iterators that give virtually no hel=
p when there's an error.<br><br>The bottom line is that "join" is an entire=
ly different "type" of operation than streaming a range. "join" is basicall=
y a "reduce" (or you could do it with std::accumulate()) operation with a f=
unction that stringifies and concatenates... that's not even in the same co=
nceptual universe as a loop that prints elements of a range individually (w=
ith optional delimiter), which is what range streaming is about. "join", fo=
r example, doesn't have to worry about I/O failure, just running out of mem=
ory... the opposite is true for range streaming: I/O failure is a major con=
cern, but memory allocation (usually) doesn't happen at all (obviously it d=
oes with a string stream). Even if it were possible to somehow overload the=
 name "join" to do both jobs, I would still be against it, because range st=
reaming is actually *not* "joining" anything - the label would be incorrect=
 for the job. That they produce similar results in some cases is actually m=
isleading. They do very different jobs, and the differences cannot be smoot=
hed out with snazzy tricks like implicit auto conversions or brushing it of=
f as a QOI problem - choosing between the different behaviours is a design =
decision, not an implementation one.<br>&nbsp;</div><blockquote class=3D"gm=
ail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc soli=
d;padding-left: 1ex;"><div dir=3D"ltr">I don't see the problem with the alg=
orithm header as any other header using it would of course include it. That=
 is, unless you are worried about compile times.</div></blockquote><div><br=
>I'm actually more worried about modules and module dependencies.<br><br>Bu=
t even if you're just thinking headers, you do <i>not</i> want the IOstream=
s library including the Algorithms library. And you do not want the Algorit=
hms library including the IOstreams header. That means it becomes the probl=
em of the programmer to decide whether it's worth including both. Frankly, =
if it were me, I wouldn't bother - if I had a file that didn't need the alg=
orithms library at all except for range streaming... i'd just write a for l=
oop (as i do now, not even using for_each()) rather than dumping the entire=
 algorithms library into my file... which is <i>exactly</i> the kind of thi=
ng we'd want to avoid.<br><br>Put another way, suppose I had a header file =
that had a class that looked something like this:<br><br><div class=3D"pret=
typrint" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(1=
87, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-wor=
d;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=
=3D"color: #800;" class=3D"styled-by-prettify">#ifndef</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> include_guard<br></span><span =
style=3D"color: #800;" class=3D"styled-by-prettify">#define</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> include_guard<br><br></sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">#include</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #080;" class=3D"styled-by-prettify">&lt;iosfwd&gt;</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span styl=
e=3D"color: #800;" class=3D"styled-by-prettify">#include</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #080;" class=3D"styled-by-prettify">&lt;vector&gt;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">namespace</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> ns </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">template</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">typename</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">class</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> something<br></sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </span><span=
 style=3D"color: #800;" class=3D"styled-by-prettify">// stuff</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; std</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify">T</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> data_</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br>&nbsp; <br>&nbsp; </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">template</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">typename</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">CharT</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">typename</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"style=
d-by-prettify">Traits</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br>&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">friend</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #008;" class=3D"styled-by-prettify">operator</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">&lt;&lt;(</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">basic_ostream</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #606=
;" class=3D"styled-by-prettify">CharT</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-p=
rettify">Traits</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">&gt;&amp;,</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> something</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">T=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">const</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&amp;)</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">-&gt;</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br>&nbsp; &nbsp; std</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">basic_ostream</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #606;" =
class=3D"styled-by-prettify">CharT</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pret=
tify">Traits</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;&am=
p;;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">template</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">typename</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> T</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">typename</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Char=
T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #606;" class=3D"styled-by-prettify">Traits</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">&gt;</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">operator</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">&lt;&lt;(</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:=
:</span><span style=3D"color: #000;" class=3D"styled-by-prettify">basic_ost=
ream</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</=
span><span style=3D"color: #606;" class=3D"styled-by-prettify">CharT</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #606;" class=3D"styled-by-prettify">Traits</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">&gt;&amp;</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">out</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> something</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">const</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> s</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">-&gt;</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br>&nbsp; std</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">basic_ostream</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">&lt;</span><span style=3D"color: #606;" class=3D"styled-by-p=
rettify">CharT</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #606;" class=3D"styled-by-prettify">Traits</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">&gt;&amp;;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">for</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">const<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> i </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> s</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>&nbsp; &nbsp; </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">out</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> s </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">' =
'</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; <br>&nb=
sp; </span><span style=3D"color: #008;" class=3D"styled-by-prettify">return=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">out</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br><br></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pret=
tify">// namespace ns</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br><br></span><span style=3D"color: #800;" class=3D"styled-by-p=
rettify">#endif</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// i=
nclude_guard</span></div></code></div><br>That's a pretty plausible header =
for a pretty realistic class type, with minimal dependencies for fast compi=
ling in huge projects.<br><br>Now I want to upgrade this to use range strea=
ming, to get multiple benefits: simplicity, safety, the ability to add deli=
miters, and proper handling of error conditions. If range streaming gets fo=
rward-declared in &lt;iosfwd&gt; and actually defined in &lt;ostream&gt; an=
d &lt;istream&gt; (for output and input versions respectively) as I would h=
ope, then the only change I would have to make is replacing the body of the=
 inserter function with "return out &lt;&lt; std::stream_range(s, ',');". B=
ut if it ends up in &lt;algorithm&gt; (as join() or whatever), then now i h=
ave to include the *entire* algorithms library... for one measly function. =
That's just ridiculous.<br><br>Here's another way to look at it. Suppose I =
have a custom replacement algorithms library - &lt;my_algorthims&gt; rather=
 than &lt;algorithms&gt;, or maybe just a link in the file system so &lt;al=
gorithm&gt; points to the new library - that replaces the standard algorith=
ms library... maybe it has neat parallelization functionality, or maybe it =
has extra debugging features for the testing phase. If I am forced to inclu=
de &lt;algorithm&gt; *just* to get convenient streaming for ranges in types=
 like the one above, then the decision of which algorithm library to includ=
e will have to be made in that header (either that or it will have to effec=
tively replicate the functionality of range streaming)... rather than at pl=
aces where algorithms are *actually* used... and there's no good argument f=
or why this should be okay.<br><br>Currently, the library as I've written i=
t depends only on &lt;iosfwd&gt; and &lt;utility&gt;, and it uses the latte=
r *only* for forward(), which means that the *entire* library can be entire=
ly contained within IOStreams with no other dependencies. And i haven't sat=
 down and worked it out yet (because i'm still adding functionality), but i=
 believe that it *might* be possible that the five functions i've mentioned=
 - stream_range(output), overwrite, back_insert, front_insert, and insert -=
 can be forward declared in &lt;iosfwd&gt;, then stream_range(output) can b=
e implemented in &lt;ostream&gt; and the other four in &lt;istream&gt; (dep=
ends on whether I can implement the front/back inserter stuff without needi=
ng the range library or type traits or whatever). Or, at the worst case, it=
 can all be in &lt;iomanip&gt;. There's just no reason to bring &lt;algorit=
hm&gt; - which is a *very* heavyweight header - into the mix.<br>&nbsp;</di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">But you may=
 be right in that the istream shifting into a container is important enough=
 to warrant a separate functionality. I don't like the separate function na=
mes though, and offer that the basic function could take a template templat=
e parameter which defaults to back_inserter.</div></blockquote><div><br>Eh,=
 that's ultimately a naming issue, which is a low priority for me. I want t=
o figure out *what* it should do... then *how* it should do it... and only =
*then*, once all that is dealt with, worry about the name to slap on it.<br=
><br>But for the record, this is supposed to be trivial, basic functionalit=
y - the kind of stuff beginners should learn in the first or second class o=
n C++. Those look a little verbose and syntactically overwrought for someth=
ing a beginner might want to use. I mean, look at the comparison:<br><br><d=
iv class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bor=
der-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word=
-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprin=
t"><span style=3D"color: #000;" class=3D"styled-by-prettify">cin </span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> elements_of</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D=
"styled-by-prettify">// 22 chars</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> elements_of</span><span style=3D"color: #080;" cla=
ss=3D"styled-by-prettify">&lt;front_inserter&gt;</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettif=
y">// 38 chars</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br>cin </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 elements_of</span><span style=3D"color: #080;" class=3D"styled-by-prettify=
">&lt;inserter&gt;</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">v=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">next</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">begin</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">v</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">),</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">10</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">));</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"=
color: #800;" class=3D"styled-by-prettify">// 52 chars</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> elements_of</span><span style=3D"c=
olor: #080;" class=3D"styled-by-prettify">&lt;replacer&gt;</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">next</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">beg=
in</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">),</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066=
;" class=3D"styled-by-prettify">10</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">),</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">next</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">begin</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">),</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" cl=
ass=3D"styled-by-prettify">20</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">));</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettif=
y">// 72 chars</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br><br></span><span style=3D"color: #800;" class=3D"styled-by-prettify=
">// versus...</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br><br>cin </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> back_insert</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">v</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #800;" class=3D"styled-by-prettify">// 22 chars (same)</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>cin </span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> front_insert</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D=
"styled-by-prettify">// 23 chars (65% shorter)</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> insert</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">next</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
 style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">v</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">),</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"style=
d-by-prettify">10</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">));</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// 37 cha=
rs (40% shorter)</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br>cin </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> overwrite</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">make_ra=
nge</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">next</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">begin</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">),</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-pretti=
fy">10</span><span style=3D"color: #660;" class=3D"styled-by-prettify">),</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">next</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">begin</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">),</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">2=
0</span><span style=3D"color: #660;" class=3D"styled-by-prettify">));</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #800;" class=3D"styled-by-prettify">// 68 chars (6% shorter)<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span>=
<span style=3D"color: #800;" class=3D"styled-by-prettify">// Or possibly</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>cin </spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> replace</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">make_range</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">next</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">begin</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">v</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>),</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #066;" class=3D"styled-by-prettify">10</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">),</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">next</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">begin</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">),</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">));</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;=
" class=3D"styled-by-prettify">// 66 chars (9% shorter)</span></div></code>=
</div><br>And that's *without* all the "std::"s.<br><br>Verbosity aside, I =
don't see how "elements_of" is clearer than "replace" or "overwrite" when w=
hat you're *actually doing* is replacing or overwriting the contents of a r=
ange. And if "elements_of" is supposed to back insert... well, then let me =
tell you exactly what will happen. Thousands of C++ teachers and help sites=
 are going to be flooded with questions about why this doesn't work:<br><br=
><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); =
border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; w=
ord-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> data</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=3D"=
color: #066;" class=3D"styled-by-prettify">24</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">];</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> elements_of</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">data</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">);</span></div></code></div><br>(And if you object to the naked =
array, replace it with std::array. Or std::forward_list, for that matter.)<=
br><br>Frankly, all other issues aside, making "back insert" the default be=
haviour would be horribly wrong-headed. One of the first things C++ beginne=
rs learn about input is that when they do:<br><br><div class=3D"prettyprint=
" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187=
, 187); border-style: solid; border-width: 1px; word-wrap: break-word;"><co=
de class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color=
: #000;" class=3D"styled-by-prettify">type x</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">;</span></div></code></div><br>that a value with the type o=
f "type" is read in from cin and it <i>replaces</i> the value of x. <i>Not<=
/i> "extends the value of x". <i>Not</i> "adds to the value of x"... <i>rep=
laces</i> (or overwrites) the value of x. You wouldn't be making things eas=
ier for beginners, you would be creating yet another "exception to the rule=
" that they'd have to memorize. The behaviour of stream input to single val=
ues is to overwrite/replace - you may think that's silly, you may not like =
it, but that's what it is. Therefore the behaviour of stream input to range=
s should be the same... unless otherwise specified.<br><br>So all else asid=
e, the default behaviour for elements_of() should be the replacing option, =
not back inserting.<br><br>Now, from my experience teaching C++, I have dis=
covered that when beginners read code, they tend to try and form vaguely En=
glish sentences from the code by reading identifiers, describing operators,=
 and dropping punctuation. When that actually works and correctly describes=
 what is happening, they grasp things easily. When it doesn't, they struggl=
e. So consider these two expressions:<br><br><div class=3D"prettyprint" sty=
le=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187=
); border-style: solid; border-width: 1px; word-wrap: break-word;"><code cl=
ass=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">cin </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> overwrite</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">values</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br>cin </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
 elements_of</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">values<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span></=
div></code></div><br>A beginner will probably read these as:<br><br>"cin...=
 input into... overwite... values"&nbsp;&nbsp;&nbsp; -&gt; "input from cin,=
 overwriting 'values'"<br>"cin... input into... elements of... values" -&gt=
; "input from cin into the elements of 'values'"<br><br>Not bad. In both ca=
ses the default way a beginner will read the code gives the correct interpr=
etation. So far so good.<br><br><div class=3D"prettyprint" style=3D"backgro=
und-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-sty=
le: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"pretty=
print"><div class=3D"subprettyprint"><span style=3D"color: #000;" class=3D"=
styled-by-prettify">cin </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> front_insert</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">values</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>ci=
n </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> elements_=
of</span><span style=3D"color: #080;" class=3D"styled-by-prettify">&lt;fron=
t_inserter&gt;</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">value=
s</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span>=
</div></code></div><br>Which will probably be read as:<br><br>"cin... input=
 into... front insert... values"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt; "input fr=
om cin and front insert into 'values'"<br>"cin... input into... elements of=
.... front inserter... values" -&gt; "what? elements of front inserter?<br>&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp; so insert input from cin in front of each element of '=
values'?"<br><br>You're assuming "elements_of&lt;front_inserter&gt;(values)=
" will be read as "elements of { front inserter values }" and not "{ elemen=
ts of front inserter } values". Let me assure you, assumptions like that wi=
ll only lead to grief when you're trying to teach beginners.<br><br>Even mo=
re infuriating for me as a teacher will be trying to explain how these thin=
gs work. Imagine you're only three or four classes in - you've covered vari=
ables (they understand vector&lt;T&gt; as "a variably-sized bunch of T valu=
es", but nothing more), basic functions, references, simple classes (basica=
lly POD strucs), and now it's time for input. You've explained that:<br><br=
><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); =
border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; w=
ord-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> n</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> n</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">;</span></div></code></div><br>really just tran=
slates into something that looks like:<br><br><div class=3D"prettyprint" st=
yle=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 18=
7); border-style: solid; border-width: 1px; word-wrap: break-word;"><code c=
lass=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">operator</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">&gt;&gt;(</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">istream</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&amp;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">i=
n</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> i</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">-&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> istream</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">&amp;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><b=
r></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </span=
><span style=3D"color: #800;" class=3D"styled-by-prettify">// magic to read=
 characters from in and convert them to an int value,</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D=
"color: #800;" class=3D"styled-by-prettify">// which gets put in i.</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> n</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">operator</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">&gt;&gt;(</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">cin</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> n</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">);</span></div></=
code></div><br>and they grasp this much. (Obviously you wouldn't mention th=
e myriad complications involved in *really* writing that function (sometime=
s I've "demonstrated" the function using getline() and atoi() - nowadays i =
suppose i'd use stoi()). It's only class 3 or 4 after all. But at least thi=
s much is enough for the beginners to grasp, and even riff on, to a limited=
 degree.) Now it's time to read ranges.<br><br>I can show a beginner:<br><b=
r><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250);=
 border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; =
word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subpretty=
print"><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> values </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> vector</span><span style=
=3D"color: #080;" class=3D"styled-by-prettify">&lt;int&gt;</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;"=
 class=3D"styled-by-prettify">1</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">2</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #066;" class=3D"styled-by-prettify">3</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=
=3D"styled-by-prettify">4</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><b=
r>cin </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;=
&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> overw=
rite</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">values</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> back_insert</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">values</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br>cin </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> insert</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">values</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">begin</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">values</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">+</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by=
-prettify">3</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">);</span></div></code></div><br>and not only will they understand what is=
 happening... <i>they will be able to replicate it</i> with only the most b=
asic understanding of C++. I can explain to them that overwrite() returns a=
n object of a special type, and then demonstrate it like this:<br><br><div =
class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border=
-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wr=
ap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint">=
<span style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> my_overwrite_type<br=
></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; vector<=
/span><span style=3D"color: #080;" class=3D"styled-by-prettify">&lt;int&gt;=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> v</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">operator</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&gt;&gt;(</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">istream</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&amp;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">in</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> my_overwrite_type owt</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">-&gt;</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> istream</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>&nbsp; </span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">for</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> i </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> owt</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">v</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br>&nbsp; &nbsp; </span><span style=3D"color: #008;" class=3D"styl=
ed-by-prettify">in</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> i<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> my_overwrite</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">vector</span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">&lt;int&gt;</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">&amp;</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> v</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; <=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">return</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> my_overwrite_t=
ype</span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br><br>cin </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> my_overwrite</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">values</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">);</span></div></code></div><br>That is all done with only=
 the most basic and trivial C++ constructs. After demonstrating and explain=
ing that, I can then send them off with a challenge to duplicate back_inser=
t(), and (for bonus points) insert()... *and they can do it* (assuming i've=
 told them about vector::push_back() and vector::insert()). In fact, after =
we've covered basic template classes and functions, I can let them have at =
it again, this time writing my_overwrite() and my_back_insert() to take *an=
y* type of range. Obviously their code won't be able to perfectly replace t=
he actual overwrite() and back_insert() until they've covered quite a bit m=
ore... but that's a hell of a lot of ground they can understand. *That* is =
what a facility intended for use by beginners should be like - something th=
ey can understand, even if only in broad terms.<br><br>Now, let's try it wi=
th elements_of(). I show them this:<br><br><div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
 border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;=
" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> values </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> vector</span><span style=3D"color: #080;" class=3D"styled=
-by-prettify">&lt;int&gt;</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">1</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">2</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"=
styled-by-prettify">3</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">4</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>cin </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">&gt;&gt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> elements_of</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify">values</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"><br>cin </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> elements_of</span><span style=3D"color: #080;" class=3D"sty=
led-by-prettify">&lt;back_inserter&gt;</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">values</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br>cin </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">&gt;&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> elements_of</span><span style=3D"color: #080;" class=3D"styled-by-prett=
ify">&lt;inserter&gt;</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">values</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify">values</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">+</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify"=
>3</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span=
></div></code></div><br>How on earth would I explain how <i>these</i> work =
to beginners? Understanding what's going on requires not just templates, bu=
t specialization (technically, <i>partial</i> specialization) and overloadi=
ng template functions <i>at least</i> - not to mention the template templat=
e structure you described. Hell, I'm a very experienced C++ programmer, and=
 <i>I</i> am balking at implementing this.<br><br>And for what do we need a=
ll this syntactic chicanery? What do we gain? The declarations just get lon=
ger and unnecessarily verbose (is "back_insert(v)" really less clear than "=
elements_of&lt;back_inserter&gt;(v)")? You can't make a single elements_of&=
lt;T&gt;() with T being a "traits" type that changes the behaviour, because=
 the different functions have different signatures, so now you're into the =
realm of variadic template functions (at least). Is it really necessary to =
have a single range I/O function that allows you to plug in behaviours? Why=
? Is there really any demand for anything beyond simply overwriting and ins=
erting at the front, back, or somewhere in the middle? (And in the freakish=
ly rare case where someone wants to do something different, wouldn't a rang=
e adaptor be a better option than a custom insert function? It would then b=
e applicable to range-based algorithms, too.) And you're not really making =
less new identifiers in the std namespace, because back_inserter, front_ins=
erter, and inserter already exist as function names. You'd need new names f=
or all of those, *plus* elements_of. If you want to keep those names, I don=
't think your proposed syntax is even possible (and if it is, it seems like=
ly to be problematic due to clashes with the existing functions).<br><br>Fo=
r now, I'm focusing on figuring out the desired behaviour of these faciliti=
es - the current names are just provisional (I don't really like "stream_ra=
nge", for example), and I was intending to put that off until after I'd act=
ually had a paper to submit. If you can actually make the element_of syntax=
 compile (I'd say don't bother worrying about the details of the behaviour,=
 such as formatting and error handling, just make it work in the most simpl=
e cases, just to show the syntax works), and explain why it would be better=
, I would appreciate that.</div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_97_1425657621.1406156448524--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Thu, 24 Jul 2014 11:15:29 -0700 (PDT)
Raw View
------=_Part_684_2011747491.1406225729965
Content-Type: text/plain; charset=UTF-8

Ok, you are obviously not interested in any feedback, as you did everything
much better yourself from the start. So I rest my case.

Everyone else seems to have understood that from the onset judging from the
number of answers you received...



Den torsdagen den 24:e juli 2014 kl. 01:00:48 UTC+2 skrev Mark A. Gibbs:
>
> On Tuesday, 22 July 2014 05:01:32 UTC-4, Bengt Gustafsson wrote:
>>
>> A proposal to define an "operator auto" so that a class with "lazy"
>> semantics can be instructed to convert to a certain type (in this case
>> string) when "converted to auto", such as in your function current_roster.
>> I think is a typical usecase for that functionality.
>>
>
> Ah, I'd forgotten about that proposal. I'm wary of it, though, because it
> seems too brittle to me. I can just see someone doing:
>
> using team_roster_type = decltype(t.current_roster()); // or result_of<>
>
> team_roster_type team_before = t.current_roster();
> // ...
>
> And they might end up with the same problem. (And I say "might" because
> I'm still not clear exactly on how this auto evaluating is supposed to
> work.)
>
> Regardless, even if you solve the problem of accidentally trucking around
> proxy objects, there are still several problems with merging join() and
> range streaming (which I'll mention below).
>
>
>> I think you got things messed up in your comparison of join() and
>> stream_range() in the ostream shift example: The sole reason for having a
>> proxy object and getting the (now solved) problem with the hidden proxy
>> object was that this proxy object can be the rhs of a << operator without
>> the interveaning conversion to string! Now you claim the performance
>> penalty of join is still there. Maybe this was under the assumption that a
>> proxy object would be unacceptable and thus join just returning string.
>>
>
> Yes, I am working with the assumption that join() does what it's currently
> spec'ed to do, and stream_range() does what I'm proposing. In that case,
> the following two statements produce identical results (in some cases!) in
> the output stream sequence (for most output streams!) but they do it in
> very different ways:
>
> auto v = { 1, 2, 3, 4 };
> out << join(v, "+") << '\n';
> out << stream_range(v, "+") << '\n';
>
> The point I was making was that *both* of these two behaviours are
> useful, and *both* should be possible. Because there are situations where
> you would specifically want one or the other. I'll give two examples.
>
> Under normal circumstances, you would prefer the second statement (with
> stream_range) - it will be more efficient than joining the range into a
> string then writing the string. But if you have a logging stream, you might
> set it to have a unit buffer. If the stream has a unit buffer, the equation
> is completely different - the first statement will probably be
> significantly faster than the second. More importantly, there is no way to
> mechanically determine which way would be better - so we can't even get
> around this by calling it a QOI issue and saying implementations can check
> for whether there's a unit buffer - because which way is "right" depends on
> design factors. In some cases a programmer might *want* each element of the
> stream written individually and damn the flushing costs... in other cases a
> programmer might prefer building the string then writing the whole thing as
> one unit write. It would depend on high-level design considerations the
> language and implementation can't be privy too.
>
> Here's another tricky question - what should this code do?:
>
> out.setf(ios_base::hex, ios_base::basefield);
> out.setf(ios_base::showbase);
>
> auto v = { 1, 2, 3, 4 };
> out << join(v, "+") << '\n';
> out << stream_range(v, "+") << '\n';
>
> Using the current proposals, it does this:
>
> 1+2+3+4
> 0x1+0x2+0x3+0x4
>
> Which is "correct"? My answer is: both. It depends on what you want. And
> note that this is something that the implicit proxy auto conversion
> actually makes *worse*, because it would mean that this:
>
> auto s = join(v, "+");
> out << s;
> // "1+2+3+4";
>
> and this:
>
> out << join(v, "+");
> // "0x1+0x2+0x3+0x4"
>
> produce different results.
>
> For a less esoteric case, consider when you're trying to align data in
> columns 10 characters wide:
>
> auto v = { 1, 2, 3 };
> out.fill('_');
> out << setw(10) << join(v, "+") << '\n';
> out << setw(10) << stream_range(v, "+") << '\n';
>
> Under the current proposals, the results are:
>
> _____1+2+3
> _________1+_________2+_________3
>
> Again, which is "correct"? My answer is that both are correct, and there
> are situations where you would want either behaviour. Neither behaviour is
> particularly "weird". Sometimes you want to treat the whole range as a
> single "thing" (which is why they named the operation "join" - multiple
> things that are joined become one thing), sometimes you want to consider
> each element individually. This is why I say that "join" is an entirely
> different type of operation to streaming a range. The fact that it produces
> identical results *in some situations* is a red herring.
>
> Incidentally, it's not in the documentation yet, but the implementation on
> github already does this behaviour. Check the output.cpp test, and look for
> the Formatting tests. With the current implementation you can write (though
> I haven't tested this):
>
> auto data = make_array(
>   make_array( 1.2130, -3.5856,  8.3570,  9.3582),
>   make_array( 7.3758, -6.3573,  1.0395,  2.0118),
>   make_array(-4.4782,  2.2353,  8.0123,  5.3253)
> );
>
> cout << "   v1   |   v2   |   v3   |   v4\n";
> cout << "--------+--------+--------+--------\n";
>
> cout.precision(3);
> cout.fill(' ');
> cout.setf(ios_base::showpos);
> cout.setf(ios_base::internal, ios_base::adjustfield);
>
> for_each(begin(data), end(data), [](auto const& row)
>   { cout << ' ' << setw(6) << stream_range(row, " | ") << '\n'; });
>
> And get:
>
>    v1   |   v2   |   v3   |   v4
> --------+--------+--------+--------
>  + 1.21 | - 3.59 | + 8.36 | + 9.36
>  + 7.38 | - 6.36 | + 1.04 | + 2.01
>  - 4.48 | + 2.24 | + 8.01 | + 5.33
>
> Which ain't bad, I think.
>
> An implicit auto conversion would also torpedo the idea of being able to
> detect errors. Under the design I'm working toward, you can figure out
> (almost) exactly where and what went wrong with output like this:
>
> auto p = stream_range(v, ", "); // (1)
> if (!(out << p)
> {
>   // What went wrong? Well:
>   // if (out.bad()) there was an unrecoverable I/O error
>   // if (out.fail()) there was a recoverable I/O error
>   // p.count() will tell you exactly which element in the range v the
> error
>   // occurred at.
> }
>
> If there's an automatic conversion to string at (1), then the possibility
> of detecting how many elements were written before the error is gone, and
> we're back to the bad old days of using copy() and stream iterators that
> give virtually no help when there's an error.
>
> The bottom line is that "join" is an entirely different "type" of
> operation than streaming a range. "join" is basically a "reduce" (or you
> could do it with std::accumulate()) operation with a function that
> stringifies and concatenates... that's not even in the same conceptual
> universe as a loop that prints elements of a range individually (with
> optional delimiter), which is what range streaming is about. "join", for
> example, doesn't have to worry about I/O failure, just running out of
> memory... the opposite is true for range streaming: I/O failure is a major
> concern, but memory allocation (usually) doesn't happen at all (obviously
> it does with a string stream). Even if it were possible to somehow overload
> the name "join" to do both jobs, I would still be against it, because range
> streaming is actually *not* "joining" anything - the label would be
> incorrect for the job. That they produce similar results in some cases is
> actually misleading. They do very different jobs, and the differences
> cannot be smoothed out with snazzy tricks like implicit auto conversions or
> brushing it off as a QOI problem - choosing between the different
> behaviours is a design decision, not an implementation one.
>
>
>> I don't see the problem with the algorithm header as any other header
>> using it would of course include it. That is, unless you are worried about
>> compile times.
>>
>
> I'm actually more worried about modules and module dependencies.
>
> But even if you're just thinking headers, you do *not* want the IOstreams
> library including the Algorithms library. And you do not want the
> Algorithms library including the IOstreams header. That means it becomes
> the problem of the programmer to decide whether it's worth including both.
> Frankly, if it were me, I wouldn't bother - if I had a file that didn't
> need the algorithms library at all except for range streaming... i'd just
> write a for loop (as i do now, not even using for_each()) rather than
> dumping the entire algorithms library into my file... which is *exactly*
> the kind of thing we'd want to avoid.
>
> Put another way, suppose I had a header file that had a class that looked
> something like this:
>
> #ifndef include_guard
> #define include_guard
>
> #include <iosfwd>
> #include <vector>
>
> namespace ns {
>
> template <typename T>
> class something
> {
>   // stuff
>   std::vector<T> data_;
>
>   template <typename T, typename CharT, typename Traits>
>   friend auto operator<<(std::basic_ostream<CharT, Traits>&, something<T>
> const&) ->
>     std::basic_ostream<CharT, Traits >&;
> };
>
> template <typename T, typename CharT, typename Traits>
> auto operator<<(std::basic_ostream<CharT, Traits>& out, something<T> const
> & s) ->
>   std::basic_ostream<CharT, Traits >&;
> {
>   for (auto const& i : s)
>     out << s << ' ';
>
>   return out;
> }
>
> } // namespace ns
>
> #endif // include_guard
>
> That's a pretty plausible header for a pretty realistic class type, with
> minimal dependencies for fast compiling in huge projects.
>
> Now I want to upgrade this to use range streaming, to get multiple
> benefits: simplicity, safety, the ability to add delimiters, and proper
> handling of error conditions. If range streaming gets forward-declared in
> <iosfwd> and actually defined in <ostream> and <istream> (for output and
> input versions respectively) as I would hope, then the only change I would
> have to make is replacing the body of the inserter function with "return
> out << std::stream_range(s, ',');". But if it ends up in <algorithm> (as
> join() or whatever), then now i have to include the *entire* algorithms
> library... for one measly function. That's just ridiculous.
>
> Here's another way to look at it. Suppose I have a custom replacement
> algorithms library - <my_algorthims> rather than <algorithms>, or maybe
> just a link in the file system so <algorithm> points to the new library -
> that replaces the standard algorithms library... maybe it has neat
> parallelization functionality, or maybe it has extra debugging features for
> the testing phase. If I am forced to include <algorithm> *just* to get
> convenient streaming for ranges in types like the one above, then the
> decision of which algorithm library to include will have to be made in that
> header (either that or it will have to effectively replicate the
> functionality of range streaming)... rather than at places where algorithms
> are *actually* used... and there's no good argument for why this should be
> okay.
>
> Currently, the library as I've written it depends only on <iosfwd> and
> <utility>, and it uses the latter *only* for forward(), which means that
> the *entire* library can be entirely contained within IOStreams with no
> other dependencies. And i haven't sat down and worked it out yet (because
> i'm still adding functionality), but i believe that it *might* be possible
> that the five functions i've mentioned - stream_range(output), overwrite,
> back_insert, front_insert, and insert - can be forward declared in
> <iosfwd>, then stream_range(output) can be implemented in <ostream> and the
> other four in <istream> (depends on whether I can implement the front/back
> inserter stuff without needing the range library or type traits or
> whatever). Or, at the worst case, it can all be in <iomanip>. There's just
> no reason to bring <algorithm> - which is a *very* heavyweight header -
> into the mix.
>
>
>> But you may be right in that the istream shifting into a container is
>> important enough to warrant a separate functionality. I don't like the
>> separate function names though, and offer that the basic function could
>> take a template template parameter which defaults to back_inserter.
>>
>
> Eh, that's ultimately a naming issue, which is a low priority for me. I
> want to figure out *what* it should do... then *how* it should do it... and
> only *then*, once all that is dealt with, worry about the name to slap on
> it.
>
> But for the record, this is supposed to be trivial, basic functionality -
> the kind of stuff beginners should learn in the first or second class on
> C++. Those look a little verbose and syntactically overwrought for
> something a beginner might want to use. I mean, look at the comparison:
>
> cin >> elements_of(v); // 22 chars
> cin >> elements_of<front_inserter>(v); // 38 chars
> cin >> elements_of<inserter>(v, next(begin(v), 10)); // 52 chars
> cin >> elements_of<replacer>(v, next(begin(v), 10), next(begin(v), 20)); //
> 72 chars
>
> // versus...
>
> cin >> back_insert(v); // 22 chars (same)
> cin >> front_insert(v); // 23 chars (65% shorter)
> cin >> insert(v, next(begin(v), 10)); // 37 chars (40% shorter)
> cin >> overwrite(make_range(next(begin(v), 10), next(begin(v), 20)); //
> 68 chars (6% shorter)
> // Or possibly
> cin >> replace(make_range(next(begin(v), 10), next(begin(v), 20)); // 66
> chars (9% shorter)
>
> And that's *without* all the "std::"s.
>
> Verbosity aside, I don't see how "elements_of" is clearer than "replace"
> or "overwrite" when what you're *actually doing* is replacing or
> overwriting the contents of a range. And if "elements_of" is supposed to
> back insert... well, then let me tell you exactly what will happen.
> Thousands of C++ teachers and help sites are going to be flooded with
> questions about why this doesn't work:
>
> int data[24];
> cin >> elements_of(data);
>
> (And if you object to the naked array, replace it with std::array. Or
> std::forward_list, for that matter.)
>
> Frankly, all other issues aside, making "back insert" the default
> behaviour would be horribly wrong-headed. One of the first things C++
> beginners learn about input is that when they do:
>
> type x;
> cin >> x;
>
> that a value with the type of "type" is read in from cin and it *replaces*
> the value of x. *Not* "extends the value of x". *Not* "adds to the value
> of x"... *replaces* (or overwrites) the value of x. You wouldn't be
> making things easier for beginners, you would be creating yet another
> "exception to the rule" that they'd have to memorize. The behaviour of
> stream input to single values is to overwrite/replace - you may think
> that's silly, you may not like it, but that's what it is. Therefore the
> behaviour of stream input to ranges should be the same... unless otherwise
> specified.
>
> So all else aside, the default behaviour for elements_of() should be the
> replacing option, not back inserting.
>
> Now, from my experience teaching C++, I have discovered that when
> beginners read code, they tend to try and form vaguely English sentences
> from the code by reading identifiers, describing operators, and dropping
> punctuation. When that actually works and correctly describes what is
> happening, they grasp things easily. When it doesn't, they struggle. So
> consider these two expressions:
>
> cin >> overwrite(values);
> cin >> elements_of(values);
>
> A beginner will probably read these as:
>
> "cin... input into... overwite... values"    -> "input from cin,
> overwriting 'values'"
> "cin... input into... elements of... values" -> "input from cin into the
> elements of 'values'"
>
> Not bad. In both cases the default way a beginner will read the code gives
> the correct interpretation. So far so good.
>
> cin >> front_insert(values);
> cin >> elements_of<front_inserter>(values);
>
> Which will probably be read as:
>
> "cin... input into... front insert... values"                  -> "input
> from cin and front insert into 'values'"
> "cin... input into... elements of... front inserter... values" -> "what?
> elements of front inserter?
>                                                                    so
> insert input from cin in front of each element of 'values'?"
>
> You're assuming "elements_of<front_inserter>(values)" will be read as
> "elements of { front inserter values }" and not "{ elements of front
> inserter } values". Let me assure you, assumptions like that will only lead
> to grief when you're trying to teach beginners.
>
> Even more infuriating for me as a teacher will be trying to explain how
> these things work. Imagine you're only three or four classes in - you've
> covered variables (they understand vector<T> as "a variably-sized bunch of
> T values", but nothing more), basic functions, references, simple classes
> (basically POD strucs), and now it's time for input. You've explained that:
>
> int n;
> cin >> n;
>
> really just translates into something that looks like:
>
> auto operator>>(istream& in, int& i) -> istream&
> {
>   // magic to read characters from in and convert them to an int value,
>   // which gets put in i.
> }
>
> int n;
> operator>>(cin, n);
>
> and they grasp this much. (Obviously you wouldn't mention the myriad
> complications involved in *really* writing that function (sometimes I've
> "demonstrated" the function using getline() and atoi() - nowadays i suppose
> i'd use stoi()). It's only class 3 or 4 after all. But at least this much
> is enough for the beginners to grasp, and even riff on, to a limited
> degree.) Now it's time to read ranges.
>
> I can show a beginner:
>
> auto values = vector<int>{ 1, 2, 3, 4 };
> cin >> overwrite(values);
> cin >> back_insert(values);
> cin >> insert(values, begin(values) + 3);
>
> and not only will they understand what is happening... *they will be able
> to replicate it* with only the most basic understanding of C++. I can
> explain to them that overwrite() returns an object of a special type, and
> then demonstrate it like this:
>
> struct my_overwrite_type
> {
>   vector<int>& v;
> };
>
> auto operator>>(istream& in, my_overwrite_type owt) -> istream&
> {
>   for (auto& i : owt.v)
>     in >> i;
> }
>
> auto my_overwrite(vector<int>& v)
> {
>   return my_overwrite_type{v};
> }
>
> cin >> my_overwrite(values);
>
> That is all done with only the most basic and trivial C++ constructs.
> After demonstrating and explaining that, I can then send them off with a
> challenge to duplicate back_insert(), and (for bonus points) insert()...
> *and they can do it* (assuming i've told them about vector::push_back() and
> vector::insert()). In fact, after we've covered basic template classes and
> functions, I can let them have at it again, this time writing
> my_overwrite() and my_back_insert() to take *any* type of range. Obviously
> their code won't be able to perfectly replace the actual overwrite() and
> back_insert() until they've covered quite a bit more... but that's a hell
> of a lot of ground they can understand. *That* is what a facility intended
> for use by beginners should be like - something they can understand, even
> if only in broad terms.
>
> Now, let's try it with elements_of(). I show them this:
>
> auto values = vector<int>{ 1, 2, 3, 4 };
> cin >> elements_of(values);
> cin >> elements_of<back_inserter>(values);
> cin >> elements_of<inserter>(values, begin(values) + 3);
>
> How on earth would I explain how *these* work to beginners? Understanding
> what's going on requires not just templates, but specialization
> (technically, *partial* specialization) and overloading template
> functions *at least* - not to mention the template template structure you
> described. Hell, I'm a very experienced C++ programmer, and *I* am
> balking at implementing this.
>
> And for what do we need all this syntactic chicanery? What do we gain? The
> declarations just get longer and unnecessarily verbose (is "back_insert(v)"
> really less clear than "elements_of<back_inserter>(v)")? You can't make a
> single elements_of<T>() with T being a "traits" type that changes the
> behaviour, because the different functions have different signatures, so
> now you're into the realm of variadic template functions (at least). Is it
> really necessary to have a single range I/O function that allows you to
> plug in behaviours? Why? Is there really any demand for anything beyond
> simply overwriting and inserting at the front, back, or somewhere in the
> middle? (And in the freakishly rare case where someone wants to do
> something different, wouldn't a range adaptor be a better option than a
> custom insert function? It would then be applicable to range-based
> algorithms, too.) And you're not really making less new identifiers in the
> std namespace, because back_inserter, front_inserter, and inserter already
> exist as function names. You'd need new names for all of those, *plus*
> elements_of. If you want to keep those names, I don't think your proposed
> syntax is even possible (and if it is, it seems likely to be problematic
> due to clashes with the existing functions).
>
> For now, I'm focusing on figuring out the desired behaviour of these
> facilities - the current names are just provisional (I don't really like
> "stream_range", for example), and I was intending to put that off until
> after I'd actually had a paper to submit. If you can actually make the
> element_of syntax compile (I'd say don't bother worrying about the details
> of the behaviour, such as formatting and error handling, just make it work
> in the most simple cases, just to show the syntax works), and explain why
> it would be better, I would appreciate that.
>

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_684_2011747491.1406225729965
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Ok, you are obviously not interested in any feedback, as y=
ou did everything much better yourself from the start. So I rest my case.&n=
bsp;<div><br></div><div>Everyone else seems to have understood that from th=
e onset judging from the number of answers you received...<div><br></div><d=
iv><br><br>Den torsdagen den 24:e juli 2014 kl. 01:00:48 UTC+2 skrev Mark A=
.. Gibbs:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On Tu=
esday, 22 July 2014 05:01:32 UTC-4, Bengt Gustafsson  wrote:<blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc=
 solid;padding-left:1ex"><div dir=3D"ltr">A proposal to define an "operator=
 auto" so that a class with "lazy" semantics can be instructed to convert t=
o a certain type (in this case string) when "converted to auto", such as in=
 your function current_roster. I think is a typical usecase for that functi=
onality.</div></blockquote><div><br>Ah, I'd forgotten about that proposal. =
I'm wary of it, though, because it seems too brittle to me. I can just see =
someone doing:<br><br><div style=3D"background-color:rgb(250,250,250);borde=
r-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:brea=
k-word"><code><div><span style=3D"color:#008">using</span><span style=3D"co=
lor:#000"> team_roster_type </span><span style=3D"color:#660">=3D</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#008">decltype</span><=
span style=3D"color:#660">(</span><span style=3D"color:#000">t</span><span =
style=3D"color:#660">.</span><span style=3D"color:#000">current_roster</spa=
n><span style=3D"color:#660">());</span><span style=3D"color:#000"> </span>=
<span style=3D"color:#800">// or result_of&lt;&gt;</span><span style=3D"col=
or:#000"><br><br>team_roster_type team_before </span><span style=3D"color:#=
660">=3D</span><span style=3D"color:#000"> t</span><span style=3D"color:#66=
0">.</span><span style=3D"color:#000">current_roster</span><span style=3D"c=
olor:#660">();</span><span style=3D"color:#000"><br></span><span style=3D"c=
olor:#800">// ...</span></div></code></div><br>And they might end up with t=
he same problem. (And I say "might" because I'm still not clear exactly on =
how this auto evaluating is supposed to work.)<br><br>Regardless, even if y=
ou solve the problem of accidentally trucking around proxy objects, there a=
re still several problems with merging join() and range streaming (which I'=
ll mention below).<br>&nbsp;</div><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr">I think you got things messed up in your comparison of jo=
in() and stream_range() in the ostream shift example: The sole reason for h=
aving a proxy object and getting the (now solved) problem with the hidden p=
roxy object was that this proxy object can be the rhs of a &lt;&lt; operato=
r without the interveaning conversion to string! Now you claim the performa=
nce penalty of join is still there. Maybe this was under the assumption tha=
t a proxy object would be unacceptable and thus join just returning string.=
</div></blockquote><div><br>Yes, I am working with the assumption that join=
() does what it's currently spec'ed to do, and stream_range() does what I'm=
 proposing. In that case, the following two statements produce identical re=
sults (in some cases!) in the output stream sequence (for most output strea=
ms!) but they do it in very different ways:<br><br><div style=3D"background=
-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bo=
rder-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">=
auto</span><span style=3D"color:#000"> v </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> </span><span style=3D"color:#660">{</=
span><span style=3D"color:#000"> </span><span style=3D"color:#066">1</span>=
<span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span=
 style=3D"color:#066">2</span><span style=3D"color:#660">,</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#066">3</span><span style=3D"=
color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color=
:#066">4</span><span style=3D"color:#000"> </span><span style=3D"color:#660=
">};</span><span style=3D"color:#000"><br></span><span style=3D"color:#008"=
>out</span><span style=3D"color:#000"> </span><span style=3D"color:#660">&l=
t;&lt;</span><span style=3D"color:#000"> join</span><span style=3D"color:#6=
60">(</span><span style=3D"color:#000">v</span><span style=3D"color:#660">,=
</span><span style=3D"color:#000"> </span><span style=3D"color:#080">"+"</s=
pan><span style=3D"color:#660">)</span><span style=3D"color:#000"> </span><=
span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> </span=
><span style=3D"color:#080">'\n'</span><span style=3D"color:#660">;</span><=
span style=3D"color:#000"><br></span><span style=3D"color:#008">out</span><=
span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&lt;</span=
><span style=3D"color:#000"> stream_range</span><span style=3D"color:#660">=
(</span><span style=3D"color:#000">v</span><span style=3D"color:#660">,</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#080">"+"</span>=
<span style=3D"color:#660">)</span><span style=3D"color:#000"> </span><span=
 style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#080">'\n'</span><span style=3D"color:#660">;</span></div=
></code></div><br>The point I was making was that <i>both</i> of these two =
behaviours are useful, and <i>both</i> should be possible. Because there ar=
e situations where you would specifically want one or the other. I'll give =
two examples.<br><br>Under normal circumstances, you would prefer the secon=
d statement (with stream_range) - it will be more efficient than joining th=
e range into a string then writing the string. But if you have a logging st=
ream, you might set it to have a unit buffer. If the stream has a unit buff=
er, the equation is completely different - the first statement will probabl=
y be significantly faster than the second. More importantly, there is no wa=
y to mechanically determine which way would be better - so we can't even ge=
t around this by calling it a QOI issue and saying implementations can chec=
k for whether there's a unit buffer - because which way is "right" depends =
on design factors. In some cases a programmer might *want* each element of =
the stream written individually and damn the flushing costs... in other cas=
es a programmer might prefer building the string then writing the whole thi=
ng as one unit write. It would depend on high-level design considerations t=
he language and implementation can't be privy too.<br><br>Here's another tr=
icky question - what should this code do?:<br><br><div style=3D"background-=
color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bor=
der-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">o=
ut</span><span style=3D"color:#660">.</span><span style=3D"color:#000">setf=
</span><span style=3D"color:#660">(</span><span style=3D"color:#000">ios_ba=
se</span><span style=3D"color:#660">::</span><span style=3D"color:#000">hex=
</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> ios_b=
ase</span><span style=3D"color:#660">::</span><span style=3D"color:#000">ba=
sefield</span><span style=3D"color:#660">);</span><span style=3D"color:#000=
"><br></span><span style=3D"color:#008">out</span><span style=3D"color:#660=
">.</span><span style=3D"color:#000">setf</span><span style=3D"color:#660">=
(</span><span style=3D"color:#000">ios_base</span><span style=3D"color:#660=
">::</span><span style=3D"color:#000">showbase</span><span style=3D"color:#=
660">);</span><span style=3D"color:#000"><br><br></span><span style=3D"colo=
r:#008">auto</span><span style=3D"color:#000"> v </span><span style=3D"colo=
r:#660">=3D</span><span style=3D"color:#000"> </span><span style=3D"color:#=
660">{</span><span style=3D"color:#000"> </span><span style=3D"color:#066">=
1</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </sp=
an><span style=3D"color:#066">2</span><span style=3D"color:#660">,</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#066">3</span><span s=
tyle=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#066">4</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#660">};</span><span style=3D"color:#000"><br></span><span style=3D"co=
lor:#008">out</span><span style=3D"color:#000"> </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> join</span><span style=3D=
"color:#660">(</span><span style=3D"color:#000">v</span><span style=3D"colo=
r:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#08=
0">"+"</span><span style=3D"color:#660">)</span><span style=3D"color:#000">=
 </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000=
"> </span><span style=3D"color:#080">'\n'</span><span style=3D"color:#660">=
;</span><span style=3D"color:#000"><br></span><span style=3D"color:#008">ou=
t</span><span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&=
lt;</span><span style=3D"color:#000"> stream_range</span><span style=3D"col=
or:#660">(</span><span style=3D"color:#000">v</span><span style=3D"color:#6=
60">,</span><span style=3D"color:#000"> </span><span style=3D"color:#080">"=
+"</span><span style=3D"color:#660">)</span><span style=3D"color:#000"> </s=
pan><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> <=
/span><span style=3D"color:#080">'\n'</span><span style=3D"color:#660">;</s=
pan></div></code></div><br>Using the current proposals, it does this:<br><b=
r><span style=3D"font-family:courier new,monospace">1+2+3+4<br>0x1+0x2+0x3+=
0x4</span><br><br>Which is "correct"? My answer is: both. It depends on wha=
t you want. And note that this is something that the implicit proxy auto co=
nversion actually makes <i>worse</i>, because it would mean that this:<br><=
br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187=
,187);border-style:solid;border-width:1px;word-wrap:break-word"><code><div>=
<span style=3D"color:#008">auto</span><span style=3D"color:#000"> s </span>=
<span style=3D"color:#660">=3D</span><span style=3D"color:#000"> join</span=
><span style=3D"color:#660">(</span><span style=3D"color:#000">v</span><spa=
n style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#080">"+"</span><span style=3D"color:#660">);</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#008">out</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">&lt;&lt;</span><span sty=
le=3D"color:#000"> s</span><span style=3D"color:#660">;</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#800">// "1+2+3+4";</span><=
/div></code></div><br>and this:<br><br><div style=3D"background-color:rgb(2=
50,250,250);border-color:rgb(187,187,187);border-style:solid;border-width:1=
px;word-wrap:break-word"><code><div><span style=3D"color:#008">out</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&lt;</span>=
<span style=3D"color:#000"> join</span><span style=3D"color:#660">(</span><=
span style=3D"color:#000">v</span><span style=3D"color:#660">,</span><span =
style=3D"color:#000"> </span><span style=3D"color:#080">"+"</span><span sty=
le=3D"color:#660">);</span><span style=3D"color:#000"><br></span><span styl=
e=3D"color:#800">// "0x1+0x2+0x3+0x4"</span></div></code></div><br>produce =
different results.<br><br>For a less esoteric case, consider when you're tr=
ying to align data in columns 10 characters wide:<br><br><div style=3D"back=
ground-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:so=
lid;border-width:1px;word-wrap:break-word"><code><div><span style=3D"color:=
#008">auto</span><span style=3D"color:#000"> v </span><span style=3D"color:=
#660">=3D</span><span style=3D"color:#000"> </span><span style=3D"color:#66=
0">{</span><span style=3D"color:#000"> </span><span style=3D"color:#066">1<=
/span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span=
><span style=3D"color:#066">2</span><span style=3D"color:#660">,</span><spa=
n style=3D"color:#000"> </span><span style=3D"color:#066">3</span><span sty=
le=3D"color:#000"> </span><span style=3D"color:#660">};</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#008">out</span><span style=
=3D"color:#660">.</span><span style=3D"color:#000">fill</span><span style=
=3D"color:#660">(</span><span style=3D"color:#080">'_'</span><span style=3D=
"color:#660">);</span><span style=3D"color:#000"><br></span><span style=3D"=
color:#008">out</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#660">&lt;&lt;</span><span style=3D"color:#000"> setw</span><span style=
=3D"color:#660">(</span><span style=3D"color:#066">10</span><span style=3D"=
color:#660">)</span><span style=3D"color:#000"> </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> join</span><span style=3D=
"color:#660">(</span><span style=3D"color:#000">v</span><span style=3D"colo=
r:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#08=
0">"+"</span><span style=3D"color:#660">)</span><span style=3D"color:#000">=
 </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000=
"> </span><span style=3D"color:#080">'\n'</span><span style=3D"color:#660">=
;</span><span style=3D"color:#000"><br></span><span style=3D"color:#008">ou=
t</span><span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&=
lt;</span><span style=3D"color:#000"> setw</span><span style=3D"color:#660"=
>(</span><span style=3D"color:#066">10</span><span style=3D"color:#660">)</=
span><span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&lt;=
</span><span style=3D"color:#000"> stream_range</span><span style=3D"color:=
#660">(</span><span style=3D"color:#000">v</span><span style=3D"color:#660"=
>,</span><span style=3D"color:#000"> </span><span style=3D"color:#080">"+"<=
/span><span style=3D"color:#660">)</span><span style=3D"color:#000"> </span=
><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> </sp=
an><span style=3D"color:#080">'\n'</span><span style=3D"color:#660">;</span=
></div></code></div><br>Under the current proposals, the results are:<br><b=
r><span style=3D"font-family:courier new,monospace">_____1+2+3<br>_________=
1+_________2+________<wbr>_3</span><br><br>Again, which is "correct"? My an=
swer is that both are correct, and there are situations where you would wan=
t either behaviour. Neither behaviour is particularly "weird". Sometimes yo=
u want to treat the whole range as a single "thing" (which is why they name=
d the operation "join" - multiple things that are joined become one thing),=
 sometimes you want to consider each element individually. This is why I sa=
y that "join" is an entirely different type of operation to streaming a ran=
ge. The fact that it produces identical results *in some situations* is a r=
ed herring.<br><br>Incidentally, it's not in the documentation yet, but the=
 implementation on github already does this behaviour. Check the output.cpp=
 test, and look for the Formatting tests. With the current implementation y=
ou can write (though I haven't tested this):<br><br><div style=3D"backgroun=
d-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;b=
order-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#008"=
>auto</span><span style=3D"color:#000"> data </span><span style=3D"color:#6=
60">=3D</span><span style=3D"color:#000"> make_array</span><span style=3D"c=
olor:#660">(</span><span style=3D"color:#000"><br>&nbsp; make_array</span><=
span style=3D"color:#660">(</span><span style=3D"color:#000"> </span><span =
style=3D"color:#066">1.2130</span><span style=3D"color:#660">,</span><span =
style=3D"color:#000"> </span><span style=3D"color:#660">-</span><span style=
=3D"color:#066">3.5856</span><span style=3D"color:#660">,</span><span style=
=3D"color:#000"> &nbsp;</span><span style=3D"color:#066">8.3570</span><span=
 style=3D"color:#660">,</span><span style=3D"color:#000"> &nbsp;</span><spa=
n style=3D"color:#066">9.3582</span><span style=3D"color:#660">),</span><sp=
an style=3D"color:#000"><br>&nbsp; make_array</span><span style=3D"color:#6=
60">(</span><span style=3D"color:#000"> </span><span style=3D"color:#066">7=
..3758</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> =
</span><span style=3D"color:#660">-</span><span style=3D"color:#066">6.3573=
</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> &nbsp=
;</span><span style=3D"color:#066">1.0395</span><span style=3D"color:#660">=
,</span><span style=3D"color:#000"> &nbsp;</span><span style=3D"color:#066"=
>2.0118</span><span style=3D"color:#660">),</span><span style=3D"color:#000=
"><br>&nbsp; make_array</span><span style=3D"color:#660">(-</span><span sty=
le=3D"color:#066">4.4782</span><span style=3D"color:#660">,</span><span sty=
le=3D"color:#000"> &nbsp;</span><span style=3D"color:#066">2.2353</span><sp=
an style=3D"color:#660">,</span><span style=3D"color:#000"> &nbsp;</span><s=
pan style=3D"color:#066">8.0123</span><span style=3D"color:#660">,</span><s=
pan style=3D"color:#000"> &nbsp;</span><span style=3D"color:#066">5.3253</s=
pan><span style=3D"color:#660">)</span><span style=3D"color:#000"><br></spa=
n><span style=3D"color:#660">);</span><span style=3D"color:#000"><br><br>co=
ut </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#0=
00"> </span><span style=3D"color:#080">" &nbsp; v1 &nbsp; | &nbsp; v2 &nbsp=
; | &nbsp; v3 &nbsp; | &nbsp; v4\n"</span><span style=3D"color:#660">;</spa=
n><span style=3D"color:#000"><br>cout </span><span style=3D"color:#660">&lt=
;&lt;</span><span style=3D"color:#000"> </span><span style=3D"color:#080">"=
--------+--------+--------+--<wbr>------\n"</span><span style=3D"color:#660=
">;</span><span style=3D"color:#000"><br><br>cout</span><span style=3D"colo=
r:#660">.</span><span style=3D"color:#000">precision</span><span style=3D"c=
olor:#660">(</span><span style=3D"color:#066">3</span><span style=3D"color:=
#660">);</span><span style=3D"color:#000"><br>cout</span><span style=3D"col=
or:#660">.</span><span style=3D"color:#000">fill</span><span style=3D"color=
:#660">(</span><span style=3D"color:#080">' '</span><span style=3D"color:#6=
60">);</span><span style=3D"color:#000"><br>cout</span><span style=3D"color=
:#660">.</span><span style=3D"color:#000">setf</span><span style=3D"color:#=
660">(</span><span style=3D"color:#000">ios_base</span><span style=3D"color=
:#660">::</span><span style=3D"color:#000">showpos</span><span style=3D"col=
or:#660">);</span><span style=3D"color:#000"><br>cout</span><span style=3D"=
color:#660">.</span><span style=3D"color:#000">setf</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">ios_base</span><span style=3D"=
color:#660">::</span><span style=3D"color:#008">internal</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"> ios_base</span><span st=
yle=3D"color:#660">::</span><span style=3D"color:#000">adjustfield</span><s=
pan style=3D"color:#660">);</span><span style=3D"color:#000"><br><br>for_ea=
ch</span><span style=3D"color:#660">(</span><span style=3D"color:#008">begi=
n</span><span style=3D"color:#660">(</span><span style=3D"color:#000">data<=
/span><span style=3D"color:#660">),</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#008">end</span><span style=3D"color:#660">(</span><=
span style=3D"color:#000">data</span><span style=3D"color:#660">),</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#660">[](</span><span=
 style=3D"color:#008">auto</span><span style=3D"color:#000"> </span><span s=
tyle=3D"color:#008">const</span><span style=3D"color:#660">&amp;</span><spa=
n style=3D"color:#000"> row</span><span style=3D"color:#660">)</span><span =
style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#660">{</span><=
span style=3D"color:#000"> cout </span><span style=3D"color:#660">&lt;&lt;<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#080">' '</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&lt;</=
span><span style=3D"color:#000"> setw</span><span style=3D"color:#660">(</s=
pan><span style=3D"color:#066">6</span><span style=3D"color:#660">)</span><=
span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&lt;</span=
><span style=3D"color:#000"> stream_range</span><span style=3D"color:#660">=
(</span><span style=3D"color:#000">row</span><span style=3D"color:#660">,</=
span><span style=3D"color:#000"> </span><span style=3D"color:#080">" | "</s=
pan><span style=3D"color:#660">)</span><span style=3D"color:#000"> </span><=
span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> </span=
><span style=3D"color:#080">'\n'</span><span style=3D"color:#660">;</span><=
span style=3D"color:#000"> </span><span style=3D"color:#660">});</span></di=
v></code></div><br>And get:<br><br><span style=3D"font-family:courier new,m=
onospace">&nbsp;&nbsp; v1&nbsp;&nbsp; |&nbsp;&nbsp; v2&nbsp;&nbsp; |&nbsp;&=
nbsp; v3&nbsp;&nbsp; |&nbsp;&nbsp; v4<br>--------+--------+--------+---<wbr=
>-----<br>&nbsp;+ 1.21 | - 3.59 | + 8.36 | + 9.36<br>&nbsp;+ 7.38 | - 6.36 =
| + 1.04 | + 2.01<br>&nbsp;- 4.48 | + 2.24 | + 8.01 | + 5.33</span><br><br>=
Which ain't bad, I think.<br><br>An implicit auto conversion would also tor=
pedo the idea of being able to detect errors. Under the design I'm working =
toward, you can figure out (almost) exactly where and what went wrong with =
output like this:<br><br><div style=3D"background-color:rgb(250,250,250);bo=
rder-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:b=
reak-word"><code><div><span style=3D"color:#008">auto</span><span style=3D"=
color:#000"> p </span><span style=3D"color:#660">=3D</span><span style=3D"c=
olor:#000"> stream_range</span><span style=3D"color:#660">(</span><span sty=
le=3D"color:#000">v</span><span style=3D"color:#660">,</span><span style=3D=
"color:#000"> </span><span style=3D"color:#080">", "</span><span style=3D"c=
olor:#660">);</span><span style=3D"color:#000"> </span><span style=3D"color=
:#800">// (1)</span><span style=3D"color:#000"><br></span><span style=3D"co=
lor:#008">if</span><span style=3D"color:#000"> </span><span style=3D"color:=
#660">(!(</span><span style=3D"color:#008">out</span><span style=3D"color:#=
000"> </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color=
:#000"> p</span><span style=3D"color:#660">)</span><span style=3D"color:#00=
0"><br></span><span style=3D"color:#660">{</span><span style=3D"color:#000"=
><br>&nbsp; </span><span style=3D"color:#800">// What went wrong? Well:</sp=
an><span style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#800">=
// if (out.bad()) there was an unrecoverable I/O error</span><span style=3D=
"color:#000"><br>&nbsp; </span><span style=3D"color:#800">// if (out.fail()=
) there was a recoverable I/O error</span><span style=3D"color:#000"><br>&n=
bsp; </span><span style=3D"color:#800">// p.count() will tell you exactly w=
hich element in the range v the error</span><span style=3D"color:#000"><br>=
&nbsp; </span><span style=3D"color:#800">// occurred at.</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#660">}</span></div></code>=
</div><br>If there's an automatic conversion to string at (1), then the pos=
sibility of detecting how many elements were written before the error is go=
ne, and we're back to the bad old days of using copy() and stream iterators=
 that give virtually no help when there's an error.<br><br>The bottom line =
is that "join" is an entirely different "type" of operation than streaming =
a range. "join" is basically a "reduce" (or you could do it with std::accum=
ulate()) operation with a function that stringifies and concatenates... tha=
t's not even in the same conceptual universe as a loop that prints elements=
 of a range individually (with optional delimiter), which is what range str=
eaming is about. "join", for example, doesn't have to worry about I/O failu=
re, just running out of memory... the opposite is true for range streaming:=
 I/O failure is a major concern, but memory allocation (usually) doesn't ha=
ppen at all (obviously it does with a string stream). Even if it were possi=
ble to somehow overload the name "join" to do both jobs, I would still be a=
gainst it, because range streaming is actually *not* "joining" anything - t=
he label would be incorrect for the job. That they produce similar results =
in some cases is actually misleading. They do very different jobs, and the =
differences cannot be smoothed out with snazzy tricks like implicit auto co=
nversions or brushing it off as a QOI problem - choosing between the differ=
ent behaviours is a design decision, not an implementation one.<br>&nbsp;</=
div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;b=
order-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">I don't see th=
e problem with the algorithm header as any other header using it would of c=
ourse include it. That is, unless you are worried about compile times.</div=
></blockquote><div><br>I'm actually more worried about modules and module d=
ependencies.<br><br>But even if you're just thinking headers, you do <i>not=
</i> want the IOstreams library including the Algorithms library. And you d=
o not want the Algorithms library including the IOstreams header. That mean=
s it becomes the problem of the programmer to decide whether it's worth inc=
luding both. Frankly, if it were me, I wouldn't bother - if I had a file th=
at didn't need the algorithms library at all except for range streaming... =
i'd just write a for loop (as i do now, not even using for_each()) rather t=
han dumping the entire algorithms library into my file... which is <i>exact=
ly</i> the kind of thing we'd want to avoid.<br><br>Put another way, suppos=
e I had a header file that had a class that looked something like this:<br>=
<br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187,18=
7,187);border-style:solid;border-width:1px;word-wrap:break-word"><code><div=
><span style=3D"color:#800">#ifndef</span><span style=3D"color:#000"> inclu=
de_guard<br></span><span style=3D"color:#800">#define</span><span style=3D"=
color:#000"> include_guard<br><br></span><span style=3D"color:#800">#includ=
e</span><span style=3D"color:#000"> </span><span style=3D"color:#080">&lt;i=
osfwd&gt;</span><span style=3D"color:#000"><br></span><span style=3D"color:=
#800">#include</span><span style=3D"color:#000"> </span><span style=3D"colo=
r:#080">&lt;vector&gt;</span><span style=3D"color:#000"><br><br></span><spa=
n style=3D"color:#008">namespace</span><span style=3D"color:#000"> ns </spa=
n><span style=3D"color:#660">{</span><span style=3D"color:#000"><br><br></s=
pan><span style=3D"color:#008">template</span><span style=3D"color:#000"> <=
/span><span style=3D"color:#660">&lt;</span><span style=3D"color:#008">type=
name</span><span style=3D"color:#000"> T</span><span style=3D"color:#660">&=
gt;</span><span style=3D"color:#000"><br></span><span style=3D"color:#008">=
class</span><span style=3D"color:#000"> something<br></span><span style=3D"=
color:#660">{</span><span style=3D"color:#000"><br>&nbsp; </span><span styl=
e=3D"color:#800">// stuff</span><span style=3D"color:#000"><br>&nbsp; std</=
span><span style=3D"color:#660">::</span><span style=3D"color:#000">vector<=
/span><span style=3D"color:#660">&lt;</span><span style=3D"color:#000">T</s=
pan><span style=3D"color:#660">&gt;</span><span style=3D"color:#000"> data_=
</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br>&n=
bsp; <br>&nbsp; </span><span style=3D"color:#008">template</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#660">&lt;</span><span style=
=3D"color:#008">typename</span><span style=3D"color:#000"> T</span><span st=
yle=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#008">typename</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#606">CharT</span><span style=3D"color:#660">,</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#008">typename</span><span st=
yle=3D"color:#000"> </span><span style=3D"color:#606">Traits</span><span st=
yle=3D"color:#660">&gt;</span><span style=3D"color:#000"><br>&nbsp; </span>=
<span style=3D"color:#008">friend</span><span style=3D"color:#000"> </span>=
<span style=3D"color:#008">auto</span><span style=3D"color:#000"> </span><s=
pan style=3D"color:#008">operator</span><span style=3D"color:#660">&lt;&lt;=
(</span><span style=3D"color:#000">std</span><span style=3D"color:#660">::<=
/span><span style=3D"color:#000">basic_ostream</span><span style=3D"color:#=
660">&lt;</span><span style=3D"color:#606"><wbr>CharT</span><span style=3D"=
color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color=
:#606">Traits</span><span style=3D"color:#660">&gt;&amp;,</span><span style=
=3D"color:#000"> something</span><span style=3D"color:#660">&lt;</span><spa=
n style=3D"color:#000">T</span><span style=3D"color:#660">&gt;</span><span =
style=3D"color:#000"> </span><span style=3D"color:#008">const</span><span s=
tyle=3D"color:#660">&amp;)</span><span style=3D"color:#000"> </span><span s=
tyle=3D"color:#660">-&gt;</span><span style=3D"color:#000"><br>&nbsp; &nbsp=
; std</span><span style=3D"color:#660">::</span><span style=3D"color:#000">=
basic_ostream</span><span style=3D"color:#660">&lt;</span><span style=3D"co=
lor:#606">CharT</span><span style=3D"color:#660">,</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#606">Traits</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#660">&gt;&amp;;</span><span style=3D=
"color:#000"><br></span><span style=3D"color:#660">};</span><span style=3D"=
color:#000"><br><br></span><span style=3D"color:#008">template</span><span =
style=3D"color:#000"> </span><span style=3D"color:#660">&lt;</span><span st=
yle=3D"color:#008">typename</span><span style=3D"color:#000"> T</span><span=
 style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span styl=
e=3D"color:#008">typename</span><span style=3D"color:#000"> </span><span st=
yle=3D"color:#606">CharT</span><span style=3D"color:#660">,</span><span sty=
le=3D"color:#000"> </span><span style=3D"color:#008">typename</span><span s=
tyle=3D"color:#000"> </span><span style=3D"color:#606">Traits</span><span s=
tyle=3D"color:#660">&gt;</span><span style=3D"color:#000"><br></span><span =
style=3D"color:#008">auto</span><span style=3D"color:#000"> </span><span st=
yle=3D"color:#008">operator</span><span style=3D"color:#660">&lt;&lt;(</spa=
n><span style=3D"color:#000">std</span><span style=3D"color:#660">::</span>=
<span style=3D"color:#000">basic_ostream</span><span style=3D"color:#660">&=
lt;</span><span style=3D"color:#606"><wbr>CharT</span><span style=3D"color:=
#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#606"=
>Traits</span><span style=3D"color:#660">&gt;&amp;</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#008">out</span><span style=3D"color:=
#660">,</span><span style=3D"color:#000"> something</span><span style=3D"co=
lor:#660">&lt;</span><span style=3D"color:#000">T</span><span style=3D"colo=
r:#660">&gt;</span><span style=3D"color:#000"> </span><span style=3D"color:=
#008">const</span><span style=3D"color:#660">&amp;</span><span style=3D"col=
or:#000"> s</span><span style=3D"color:#660">)</span><span style=3D"color:#=
000"> </span><span style=3D"color:#660">-&gt;</span><span style=3D"color:#0=
00"><br>&nbsp; std</span><span style=3D"color:#660">::</span><span style=3D=
"color:#000">basic_ostream</span><span style=3D"color:#660">&lt;</span><spa=
n style=3D"color:#606">CharT</span><span style=3D"color:#660">,</span><span=
 style=3D"color:#000"> </span><span style=3D"color:#606">Traits</span><span=
 style=3D"color:#000"> </span><span style=3D"color:#660">&gt;&amp;;</span><=
span style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><sp=
an style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#008">for</s=
pan><span style=3D"color:#000"> </span><span style=3D"color:#660">(</span><=
span style=3D"color:#008">auto</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#008">const</span><span style=3D"color:#660">&amp;</span>=
<span style=3D"color:#000"> i </span><span style=3D"color:#660">:</span><sp=
an style=3D"color:#000"> s</span><span style=3D"color:#660">)</span><span s=
tyle=3D"color:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#008">out=
</span><span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&l=
t;</span><span style=3D"color:#000"> s </span><span style=3D"color:#660">&l=
t;&lt;</span><span style=3D"color:#000"> </span><span style=3D"color:#080">=
' '</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br=
>&nbsp; <br>&nbsp; </span><span style=3D"color:#008">return</span><span sty=
le=3D"color:#000"> </span><span style=3D"color:#008">out</span><span style=
=3D"color:#660">;</span><span style=3D"color:#000"><br></span><span style=
=3D"color:#660">}</span><span style=3D"color:#000"><br><br></span><span sty=
le=3D"color:#660">}</span><span style=3D"color:#000"> </span><span style=3D=
"color:#800">// namespace ns</span><span style=3D"color:#000"><br><br></spa=
n><span style=3D"color:#800">#endif</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#800">// include_guard</span></div></code></div><br>=
That's a pretty plausible header for a pretty realistic class type, with mi=
nimal dependencies for fast compiling in huge projects.<br><br>Now I want t=
o upgrade this to use range streaming, to get multiple benefits: simplicity=
, safety, the ability to add delimiters, and proper handling of error condi=
tions. If range streaming gets forward-declared in &lt;iosfwd&gt; and actua=
lly defined in &lt;ostream&gt; and &lt;istream&gt; (for output and input ve=
rsions respectively) as I would hope, then the only change I would have to =
make is replacing the body of the inserter function with "return out &lt;&l=
t; std::stream_range(s, ',');". But if it ends up in &lt;algorithm&gt; (as =
join() or whatever), then now i have to include the *entire* algorithms lib=
rary... for one measly function. That's just ridiculous.<br><br>Here's anot=
her way to look at it. Suppose I have a custom replacement algorithms libra=
ry - &lt;my_algorthims&gt; rather than &lt;algorithms&gt;, or maybe just a =
link in the file system so &lt;algorithm&gt; points to the new library - th=
at replaces the standard algorithms library... maybe it has neat paralleliz=
ation functionality, or maybe it has extra debugging features for the testi=
ng phase. If I am forced to include &lt;algorithm&gt; *just* to get conveni=
ent streaming for ranges in types like the one above, then the decision of =
which algorithm library to include will have to be made in that header (eit=
her that or it will have to effectively replicate the functionality of rang=
e streaming)... rather than at places where algorithms are *actually* used.=
... and there's no good argument for why this should be okay.<br><br>Current=
ly, the library as I've written it depends only on &lt;iosfwd&gt; and &lt;u=
tility&gt;, and it uses the latter *only* for forward(), which means that t=
he *entire* library can be entirely contained within IOStreams with no othe=
r dependencies. And i haven't sat down and worked it out yet (because i'm s=
till adding functionality), but i believe that it *might* be possible that =
the five functions i've mentioned - stream_range(output), overwrite, back_i=
nsert, front_insert, and insert - can be forward declared in &lt;iosfwd&gt;=
, then stream_range(output) can be implemented in &lt;ostream&gt; and the o=
ther four in &lt;istream&gt; (depends on whether I can implement the front/=
back inserter stuff without needing the range library or type traits or wha=
tever). Or, at the worst case, it can all be in &lt;iomanip&gt;. There's ju=
st no reason to bring &lt;algorithm&gt; - which is a *very* heavyweight hea=
der - into the mix.<br>&nbsp;</div><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr">But you may be right in that the istream shifting into a =
container is important enough to warrant a separate functionality. I don't =
like the separate function names though, and offer that the basic function =
could take a template template parameter which defaults to back_inserter.</=
div></blockquote><div><br>Eh, that's ultimately a naming issue, which is a =
low priority for me. I want to figure out *what* it should do... then *how*=
 it should do it... and only *then*, once all that is dealt with, worry abo=
ut the name to slap on it.<br><br>But for the record, this is supposed to b=
e trivial, basic functionality - the kind of stuff beginners should learn i=
n the first or second class on C++. Those look a little verbose and syntact=
ically overwrought for something a beginner might want to use. I mean, look=
 at the comparison:<br><br><div style=3D"background-color:rgb(250,250,250);=
border-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap=
:break-word"><code><div><span style=3D"color:#000">cin </span><span style=
=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> elements_of</spa=
n><span style=3D"color:#660">(</span><span style=3D"color:#000">v</span><sp=
an style=3D"color:#660">);</span><span style=3D"color:#000"> </span><span s=
tyle=3D"color:#800">// 22 chars</span><span style=3D"color:#000"><br>cin </=
span><span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> =
elements_of</span><span style=3D"color:#080">&lt;front_inserter&gt;</span><=
span style=3D"color:#660">(</span><span style=3D"color:#000">v</span><span =
style=3D"color:#660">)<wbr>;</span><span style=3D"color:#000"> </span><span=
 style=3D"color:#800">// 38 chars</span><span style=3D"color:#000"><br>cin =
</span><span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"=
> elements_of</span><span style=3D"color:#080">&lt;inserter&gt;</span><span=
 style=3D"color:#660">(</span><span style=3D"color:#000">v</span><span styl=
e=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"=
color:#008">next</span><span style=3D"color:#660">(</span><span style=3D"co=
lor:#008">begin</span><span style=3D"color:#660">(</span><span style=3D"col=
or:#000">v</span><span style=3D"color:#660">),</span><span style=3D"color:#=
000"> </span><span style=3D"color:#066">10</span><span style=3D"color:#660"=
>));</span><span style=3D"color:#000"> </span><span style=3D"color:#800">//=
 52 chars</span><span style=3D"color:#000"><br>cin </span><span style=3D"co=
lor:#660">&gt;&gt;</span><span style=3D"color:#000"> elements_of</span><spa=
n style=3D"color:#080">&lt;replacer&gt;</span><span style=3D"color:#660">(<=
/span><span style=3D"color:#000">v</span><span style=3D"color:#660">,</span=
><span style=3D"color:#000"> </span><span style=3D"color:#008">next</span><=
span style=3D"color:#660">(</span><span style=3D"color:#008">begin</span><s=
pan style=3D"color:#660">(</span><span style=3D"color:#000">v</span><span s=
tyle=3D"color:#660">),</span><span style=3D"color:#000"> </span><span style=
=3D"color:#066">10</span><span style=3D"color:#660">),</span><span style=3D=
"color:#000"> </span><span style=3D"color:#008">next</span><span style=3D"c=
olor:#660">(</span><span style=3D"color:#008">begin</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">v</span><span style=3D"color:#=
660">),</span><span style=3D"color:#000"> </span><span style=3D"color:#066"=
>20</span><span style=3D"color:#660">));</span><span style=3D"color:#000"> =
</span><span style=3D"color:#800">// 72 chars</span><span style=3D"color:#0=
00"><br><br></span><span style=3D"color:#800">// versus...</span><span styl=
e=3D"color:#000"><br><br>cin </span><span style=3D"color:#660">&gt;&gt;</sp=
an><span style=3D"color:#000"> back_insert</span><span style=3D"color:#660"=
>(</span><span style=3D"color:#000">v</span><span style=3D"color:#660">);</=
span><span style=3D"color:#000"> </span><span style=3D"color:#800">// 22 ch=
ars (same)</span><span style=3D"color:#000"><br>cin </span><span style=3D"c=
olor:#660">&gt;&gt;</span><span style=3D"color:#000"> front_insert</span><s=
pan style=3D"color:#660">(</span><span style=3D"color:#000">v</span><span s=
tyle=3D"color:#660">);</span><span style=3D"color:#000"> </span><span style=
=3D"color:#800">// 23 chars (65% shorter)</span><span style=3D"color:#000">=
<br>cin </span><span style=3D"color:#660">&gt;&gt;</span><span style=3D"col=
or:#000"> insert</span><span style=3D"color:#660">(</span><span style=3D"co=
lor:#000">v</span><span style=3D"color:#660">,</span><span style=3D"color:#=
000"> </span><span style=3D"color:#008">next</span><span style=3D"color:#66=
0">(</span><span style=3D"color:#008">begin</span><span style=3D"color:#660=
">(</span><span style=3D"color:#000">v</span><span style=3D"color:#660">),<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#066">10</spa=
n><span style=3D"color:#660">));</span><span style=3D"color:#000"> </span><=
span style=3D"color:#800">// 37 chars (40% shorter)</span><span style=3D"co=
lor:#000"><br>cin </span><span style=3D"color:#660">&gt;&gt;</span><span st=
yle=3D"color:#000"> overwrite</span><span style=3D"color:#660">(</span><spa=
n style=3D"color:#000">make_range</span><span style=3D"color:#660">(</span>=
<span style=3D"color:#008">next</span><span style=3D"color:#660">(</span><s=
pan style=3D"color:#008">begi<wbr>n</span><span style=3D"color:#660">(</spa=
n><span style=3D"color:#000">v</span><span style=3D"color:#660">),</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#066">10</span><span =
style=3D"color:#660">),</span><span style=3D"color:#000"> </span><span styl=
e=3D"color:#008">next</span><span style=3D"color:#660">(</span><span style=
=3D"color:#008">begin</span><span style=3D"color:#660">(</span><span style=
=3D"color:#000">v</span><span style=3D"color:#660">),</span><span style=3D"=
color:#000"> </span><span style=3D"color:#066">20</span><span style=3D"colo=
r:#660">));</span><span style=3D"color:#000"> </span><span style=3D"color:#=
800">// 68 chars (6% shorter)</span><span style=3D"color:#000"><br></span><=
span style=3D"color:#800">// Or possibly</span><span style=3D"color:#000"><=
br>cin </span><span style=3D"color:#660">&gt;&gt;</span><span style=3D"colo=
r:#000"> replace</span><span style=3D"color:#660">(</span><span style=3D"co=
lor:#000">make_range</span><span style=3D"color:#660">(</span><span style=
=3D"color:#008">next</span><span style=3D"color:#660">(</span><span style=
=3D"color:#008">begin</span><span style=3D"color:#660">(</span><span style=
=3D"color:#000"><wbr>v</span><span style=3D"color:#660">),</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#066">10</span><span style=3D=
"color:#660">),</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#008">next</span><span style=3D"color:#660">(</span><span style=3D"color=
:#008">begin</span><span style=3D"color:#660">(</span><span style=3D"color:=
#000">v</span><span style=3D"color:#660">),</span><span style=3D"color:#000=
"> </span><span style=3D"color:#066">20</span><span style=3D"color:#660">))=
;</span><span style=3D"color:#000"> </span><span style=3D"color:#800">// 66=
 chars (9% shorter)</span></div></code></div><br>And that's *without* all t=
he "std::"s.<br><br>Verbosity aside, I don't see how "elements_of" is clear=
er than "replace" or "overwrite" when what you're *actually doing* is repla=
cing or overwriting the contents of a range. And if "elements_of" is suppos=
ed to back insert... well, then let me tell you exactly what will happen. T=
housands of C++ teachers and help sites are going to be flooded with questi=
ons about why this doesn't work:<br><br><div style=3D"background-color:rgb(=
250,250,250);border-color:rgb(187,187,187);border-style:solid;border-width:=
1px;word-wrap:break-word"><code><div><span style=3D"color:#008">int</span><=
span style=3D"color:#000"> data</span><span style=3D"color:#660">[</span><s=
pan style=3D"color:#066">24</span><span style=3D"color:#660">];</span><span=
 style=3D"color:#000"><br>cin </span><span style=3D"color:#660">&gt;&gt;</s=
pan><span style=3D"color:#000"> elements_of</span><span style=3D"color:#660=
">(</span><span style=3D"color:#000">data</span><span style=3D"color:#660">=
);</span></div></code></div><br>(And if you object to the naked array, repl=
ace it with std::array. Or std::forward_list, for that matter.)<br><br>Fran=
kly, all other issues aside, making "back insert" the default behaviour wou=
ld be horribly wrong-headed. One of the first things C++ beginners learn ab=
out input is that when they do:<br><br><div style=3D"background-color:rgb(2=
50,250,250);border-color:rgb(187,187,187);border-style:solid;border-width:1=
px;word-wrap:break-word"><code><div><span style=3D"color:#000">type x</span=
><span style=3D"color:#660">;</span><span style=3D"color:#000"><br>cin </sp=
an><span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> x<=
/span><span style=3D"color:#660">;</span></div></code></div><br>that a valu=
e with the type of "type" is read in from cin and it <i>replaces</i> the va=
lue of x. <i>Not</i> "extends the value of x". <i>Not</i> "adds to the valu=
e of x"... <i>replaces</i> (or overwrites) the value of x. You wouldn't be =
making things easier for beginners, you would be creating yet another "exce=
ption to the rule" that they'd have to memorize. The behaviour of stream in=
put to single values is to overwrite/replace - you may think that's silly, =
you may not like it, but that's what it is. Therefore the behaviour of stre=
am input to ranges should be the same... unless otherwise specified.<br><br=
>So all else aside, the default behaviour for elements_of() should be the r=
eplacing option, not back inserting.<br><br>Now, from my experience teachin=
g C++, I have discovered that when beginners read code, they tend to try an=
d form vaguely English sentences from the code by reading identifiers, desc=
ribing operators, and dropping punctuation. When that actually works and co=
rrectly describes what is happening, they grasp things easily. When it does=
n't, they struggle. So consider these two expressions:<br><br><div style=3D=
"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-sty=
le:solid;border-width:1px;word-wrap:break-word"><code><div><span style=3D"c=
olor:#000">cin </span><span style=3D"color:#660">&gt;&gt;</span><span style=
=3D"color:#000"> overwrite</span><span style=3D"color:#660">(</span><span s=
tyle=3D"color:#000">values</span><span style=3D"color:#660">);</span><span =
style=3D"color:#000"><br>cin </span><span style=3D"color:#660">&gt;&gt;</sp=
an><span style=3D"color:#000"> elements_of</span><span style=3D"color:#660"=
>(</span><span style=3D"color:#000">values</span><span style=3D"color:#660"=
>);</span></div></code></div><br>A beginner will probably read these as:<br=
><br>"cin... input into... overwite... values"&nbsp;&nbsp;&nbsp; -&gt; "inp=
ut from cin, overwriting 'values'"<br>"cin... input into... elements of... =
values" -&gt; "input from cin into the elements of 'values'"<br><br>Not bad=
.. In both cases the default way a beginner will read the code gives the cor=
rect interpretation. So far so good.<br><br><div style=3D"background-color:=
rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-wi=
dth:1px;word-wrap:break-word"><code><div><span style=3D"color:#000">cin </s=
pan><span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> f=
ront_insert</span><span style=3D"color:#660">(</span><span style=3D"color:#=
000">values</span><span style=3D"color:#660">);</span><span style=3D"color:=
#000"><br>cin </span><span style=3D"color:#660">&gt;&gt;</span><span style=
=3D"color:#000"> elements_of</span><span style=3D"color:#080">&lt;front_ins=
erter&gt;</span><span style=3D"color:#660">(</span><span style=3D"color:#00=
0">va<wbr>lues</span><span style=3D"color:#660">);</span></div></code></div=
><br>Which will probably be read as:<br><br>"cin... input into... front ins=
ert... values"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt; "input from cin and front i=
nsert into 'values'"<br>"cin... input into... elements of... front inserter=
.... values" -&gt; "what? elements of front inserter?<br>&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;<wbr>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<wbr>&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp; so insert input from cin in front of each element of 'values'?=
"<br><br>You're assuming "elements_of&lt;front_inserter&gt;(<wbr>values)" w=
ill be read as "elements of { front inserter values }" and not "{ elements =
of front inserter } values". Let me assure you, assumptions like that will =
only lead to grief when you're trying to teach beginners.<br><br>Even more =
infuriating for me as a teacher will be trying to explain how these things =
work. Imagine you're only three or four classes in - you've covered variabl=
es (they understand vector&lt;T&gt; as "a variably-sized bunch of T values"=
, but nothing more), basic functions, references, simple classes (basically=
 POD strucs), and now it's time for input. You've explained that:<br><br><d=
iv style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187)=
;border-style:solid;border-width:1px;word-wrap:break-word"><code><div><span=
 style=3D"color:#008">int</span><span style=3D"color:#000"> n</span><span s=
tyle=3D"color:#660">;</span><span style=3D"color:#000"><br>cin </span><span=
 style=3D"color:#660">&gt;&gt;</span><span style=3D"color:#000"> n</span><s=
pan style=3D"color:#660">;</span></div></code></div><br>really just transla=
tes into something that looks like:<br><br><div style=3D"background-color:r=
gb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-wid=
th:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">auto</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#008">operator</=
span><span style=3D"color:#660">&gt;&gt;(</span><span style=3D"color:#000">=
istream</span><span style=3D"color:#660">&amp;</span><span style=3D"color:#=
000"> </span><span style=3D"color:#008">in</span><span style=3D"color:#660"=
>,</span><span style=3D"color:#000"> </span><span style=3D"color:#008">int<=
/span><span style=3D"color:#660">&amp;</span><span style=3D"color:#000"> i<=
/span><span style=3D"color:#660">)</span><span style=3D"color:#000"> </span=
><span style=3D"color:#660">-&gt;</span><span style=3D"color:#000"> istream=
</span><span style=3D"color:#660">&amp;</span><span style=3D"color:#000"><b=
r></span><span style=3D"color:#660">{</span><span style=3D"color:#000"><br>=
&nbsp; </span><span style=3D"color:#800">// magic to read characters from i=
n and convert them to an int value,</span><span style=3D"color:#000"><br>&n=
bsp; </span><span style=3D"color:#800">// which gets put in i.</span><span =
style=3D"color:#000"><br></span><span style=3D"color:#660">}</span><span st=
yle=3D"color:#000"><br><br></span><span style=3D"color:#008">int</span><spa=
n style=3D"color:#000"> n</span><span style=3D"color:#660">;</span><span st=
yle=3D"color:#000"><br></span><span style=3D"color:#008">operator</span><sp=
an style=3D"color:#660">&gt;&gt;(</span><span style=3D"color:#000">cin</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> n</span><s=
pan style=3D"color:#660">);</span></div></code></div><br>and they grasp thi=
s much. (Obviously you wouldn't mention the myriad complications involved i=
n *really* writing that function (sometimes I've "demonstrated" the functio=
n using getline() and atoi() - nowadays i suppose i'd use stoi()). It's onl=
y class 3 or 4 after all. But at least this much is enough for the beginner=
s to grasp, and even riff on, to a limited degree.) Now it's time to read r=
anges.<br><br>I can show a beginner:<br><br><div style=3D"background-color:=
rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-wi=
dth:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">auto</s=
pan><span style=3D"color:#000"> values </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> vector</span><span style=3D"color:#08=
0">&lt;int&gt;</span><span style=3D"color:#660">{</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#066">1</span><span style=3D"color:#66=
0">,</span><span style=3D"color:#000"> </span><span style=3D"color:#066">2<=
/span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span=
><span style=3D"color:#066">3</span><span style=3D"color:#660">,</span><spa=
n style=3D"color:#000"> </span><span style=3D"color:#066">4</span><span sty=
le=3D"color:#000"> </span><span style=3D"color:#660">};</span><span style=
=3D"color:#000"><br>cin </span><span style=3D"color:#660">&gt;&gt;</span><s=
pan style=3D"color:#000"> overwrite</span><span style=3D"color:#660">(</spa=
n><span style=3D"color:#000">values</span><span style=3D"color:#660">);</sp=
an><span style=3D"color:#000"><br>cin </span><span style=3D"color:#660">&gt=
;&gt;</span><span style=3D"color:#000"> back_insert</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">values</span><span style=3D"co=
lor:#660">);</span><span style=3D"color:#000"><br>cin </span><span style=3D=
"color:#660">&gt;&gt;</span><span style=3D"color:#000"> insert</span><span =
style=3D"color:#660">(</span><span style=3D"color:#000">values</span><span =
style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#008">begin</span><span style=3D"color:#660">(</span><span style=
=3D"color:#000">values</span><span style=3D"color:#660">)</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">+</span><span style=3D"c=
olor:#000"> </span><span style=3D"color:#066">3</span><span style=3D"color:=
#660">);</span></div></code></div><br>and not only will they understand wha=
t is happening... <i>they will be able to replicate it</i> with only the mo=
st basic understanding of C++. I can explain to them that overwrite() retur=
ns an object of a special type, and then demonstrate it like this:<br><br><=
div style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187=
);border-style:solid;border-width:1px;word-wrap:break-word"><code><div><spa=
n style=3D"color:#008">struct</span><span style=3D"color:#000"> my_overwrit=
e_type<br></span><span style=3D"color:#660">{</span><span style=3D"color:#0=
00"><br>&nbsp; vector</span><span style=3D"color:#080">&lt;int&gt;</span><s=
pan style=3D"color:#660">&amp;</span><span style=3D"color:#000"> v</span><s=
pan style=3D"color:#660">;</span><span style=3D"color:#000"><br></span><spa=
n style=3D"color:#660">};</span><span style=3D"color:#000"><br><br></span><=
span style=3D"color:#008">auto</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#008">operator</span><span style=3D"color:#660">&gt;&gt;(=
</span><span style=3D"color:#000">istream</span><span style=3D"color:#660">=
&amp;</span><span style=3D"color:#000"> </span><span style=3D"color:#008">i=
n</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> my_o=
verwrite_type owt</span><span style=3D"color:#660">)</span><span style=3D"c=
olor:#000"> </span><span style=3D"color:#660">-&gt;</span><span style=3D"co=
lor:#000"> istream</span><span style=3D"color:#660">&amp;</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span style=
=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#008">for</span><spa=
n style=3D"color:#000"> </span><span style=3D"color:#660">(</span><span sty=
le=3D"color:#008">auto</span><span style=3D"color:#660">&amp;</span><span s=
tyle=3D"color:#000"> i </span><span style=3D"color:#660">:</span><span styl=
e=3D"color:#000"> owt</span><span style=3D"color:#660">.</span><span style=
=3D"color:#000">v</span><span style=3D"color:#660">)</span><span style=3D"c=
olor:#000"><br>&nbsp; &nbsp; </span><span style=3D"color:#008">in</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#660">&gt;&gt;</span><=
span style=3D"color:#000"> i</span><span style=3D"color:#660">;</span><span=
 style=3D"color:#000"><br></span><span style=3D"color:#660">}</span><span s=
tyle=3D"color:#000"><br><br></span><span style=3D"color:#008">auto</span><s=
pan style=3D"color:#000"> my_overwrite</span><span style=3D"color:#660">(</=
span><span style=3D"color:#000">vector</span><span style=3D"color:#080">&lt=
;int&gt;</span><span style=3D"color:#660">&amp;</span><span style=3D"color:=
#000"> v</span><span style=3D"color:#660">)</span><span style=3D"color:#000=
"><br></span><span style=3D"color:#660">{</span><span style=3D"color:#000">=
<br>&nbsp; </span><span style=3D"color:#008">return</span><span style=3D"co=
lor:#000"> my_overwrite_type</span><span style=3D"color:#660">{</span><span=
 style=3D"color:#000">v</span><span style=3D"color:#660">};</span><span sty=
le=3D"color:#000"><br></span><span style=3D"color:#660">}</span><span style=
=3D"color:#000"><br><br>cin </span><span style=3D"color:#660">&gt;&gt;</spa=
n><span style=3D"color:#000"> my_overwrite</span><span style=3D"color:#660"=
>(</span><span style=3D"color:#000">values</span><span style=3D"color:#660"=
>);</span></div></code></div><br>That is all done with only the most basic =
and trivial C++ constructs. After demonstrating and explaining that, I can =
then send them off with a challenge to duplicate back_insert(), and (for bo=
nus points) insert()... *and they can do it* (assuming i've told them about=
 vector::push_back() and vector::insert()). In fact, after we've covered ba=
sic template classes and functions, I can let them have at it again, this t=
ime writing my_overwrite() and my_back_insert() to take *any* type of range=
.. Obviously their code won't be able to perfectly replace the actual overwr=
ite() and back_insert() until they've covered quite a bit more... but that'=
s a hell of a lot of ground they can understand. *That* is what a facility =
intended for use by beginners should be like - something they can understan=
d, even if only in broad terms.<br><br>Now, let's try it with elements_of()=
.. I show them this:<br><br><div style=3D"background-color:rgb(250,250,250);=
border-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap=
:break-word"><code><div><span style=3D"color:#008">auto</span><span style=
=3D"color:#000"> values </span><span style=3D"color:#660">=3D</span><span s=
tyle=3D"color:#000"> vector</span><span style=3D"color:#080">&lt;int&gt;</s=
pan><span style=3D"color:#660">{</span><span style=3D"color:#000"> </span><=
span style=3D"color:#066">1</span><span style=3D"color:#660">,</span><span =
style=3D"color:#000"> </span><span style=3D"color:#066">2</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#066">3</span><span style=3D"color:#660">,</span><span style=3D"color:=
#000"> </span><span style=3D"color:#066">4</span><span style=3D"color:#000"=
> </span><span style=3D"color:#660">};</span><span style=3D"color:#000"><br=
>cin </span><span style=3D"color:#660">&gt;&gt;</span><span style=3D"color:=
#000"> elements_of</span><span style=3D"color:#660">(</span><span style=3D"=
color:#000">values</span><span style=3D"color:#660">);</span><span style=3D=
"color:#000"><br>cin </span><span style=3D"color:#660">&gt;&gt;</span><span=
 style=3D"color:#000"> elements_of</span><span style=3D"color:#080">&lt;bac=
k_inserter&gt;</span><span style=3D"color:#660">(</span><span style=3D"colo=
r:#000">val<wbr>ues</span><span style=3D"color:#660">);</span><span style=
=3D"color:#000"><br>cin </span><span style=3D"color:#660">&gt;&gt;</span><s=
pan style=3D"color:#000"> elements_of</span><span style=3D"color:#080">&lt;=
inserter&gt;</span><span style=3D"color:#660">(</span><span style=3D"color:=
#000">values</span><span style=3D"color:#660">,</span><span style=3D"color:=
#000"> </span><span style=3D"color:#008">begin</span><span style=3D"color:#=
660">(</span><span style=3D"color:#000">values</span><span style=3D"color:#=
660">)</span><span style=3D"color:#000"> </span><span style=3D"color:#660">=
+</span><span style=3D"color:#000"> </span><span style=3D"color:#066">3</sp=
an><span style=3D"color:#660">);</span></div></code></div><br>How on earth =
would I explain how <i>these</i> work to beginners? Understanding what's go=
ing on requires not just templates, but specialization (technically, <i>par=
tial</i> specialization) and overloading template functions <i>at least</i>=
 - not to mention the template template structure you described. Hell, I'm =
a very experienced C++ programmer, and <i>I</i> am balking at implementing =
this.<br><br>And for what do we need all this syntactic chicanery? What do =
we gain? The declarations just get longer and unnecessarily verbose (is "ba=
ck_insert(v)" really less clear than "elements_of&lt;back_inserter&gt;(v)<w=
br>")? You can't make a single elements_of&lt;T&gt;() with T being a "trait=
s" type that changes the behaviour, because the different functions have di=
fferent signatures, so now you're into the realm of variadic template funct=
ions (at least). Is it really necessary to have a single range I/O function=
 that allows you to plug in behaviours? Why? Is there really any demand for=
 anything beyond simply overwriting and inserting at the front, back, or so=
mewhere in the middle? (And in the freakishly rare case where someone wants=
 to do something different, wouldn't a range adaptor be a better option tha=
n a custom insert function? It would then be applicable to range-based algo=
rithms, too.) And you're not really making less new identifiers in the std =
namespace, because back_inserter, front_inserter, and inserter already exis=
t as function names. You'd need new names for all of those, *plus* elements=
_of. If you want to keep those names, I don't think your proposed syntax is=
 even possible (and if it is, it seems likely to be problematic due to clas=
hes with the existing functions).<br><br>For now, I'm focusing on figuring =
out the desired behaviour of these facilities - the current names are just =
provisional (I don't really like "stream_range", for example), and I was in=
tending to put that off until after I'd actually had a paper to submit. If =
you can actually make the element_of syntax compile (I'd say don't bother w=
orrying about the details of the behaviour, such as formatting and error ha=
ndling, just make it work in the most simple cases, just to show the syntax=
 works), and explain why it would be better, I would appreciate that.</div>=
</div></blockquote></div></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_684_2011747491.1406225729965--

.


Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Tue, 16 Sep 2014 07:33:52 -0700 (PDT)
Raw View
------=_Part_169_1695985880.1410878033173
Content-Type: text/plain; charset=UTF-8

I have redesigned the sample implementation and added a bunch of new
features.

The output portion is a single function - write_all() - overloaded for
optional delimiters:

auto const a = std::array<char, 3>{'a', 'b', 'c'};
std::cout << std::write_all(a);
// Output: "abc"

std::cout << "{ " << std::write_all({1, 2, 3}, ", ") << " }";
// Output: "{ 1, 2, 3 }"

You can capture the range output object returned by write_all(), and query
it for information about the last write:

auto p = std::write_all(r);
std::cout << p;

if (p.next != r.end())
  std::cerr << "Error writing r. Only " << p.count << " values written.";

And, of course, formatting is properly handled:

std::cout << "{ " << setw(5) << setfill('_') <<
             std::write_all({1, 2, 3}, ", ") << " }";
// Output: "{ ____1, ____2, ____3 }"

Input consists of 8 functions. There is a generic input function - input()
- that can be customized via a traits class for any kind of input behaviour
and filtering. Then there are 4 ready-made input behaviour functions:
overwrite, back insert, front insert, and general insert (the latter 3 come
in 2 flavours - "read until you can't read anymore", and "stop after n
successful reads"). Formatting and error querying works for input, too.

For more info, I put the documentation in the source package online:
http://cpp.indi.frih.net/rangeio/

Does anyone have any comments, questions, or suggestions for what I've got
so far?

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_169_1695985880.1410878033173
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I have redesigned the sample implementation and added a bu=
nch of new features.<br><br>The output portion is a single function - write=
_all() - overloaded for optional delimiters:<br><br><div class=3D"prettypri=
nt" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 1=
87, 187); border-style: solid; border-width: 1px; word-wrap: break-word;"><=
code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">const</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> a </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">array</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">char</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066=
;" class=3D"styled-by-prettify">3</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&gt;{</span><span style=3D"color: #080;" class=3D"s=
tyled-by-prettify">'a'</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">'b'</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #080;" class=3D"styled-by-prettify">'c'</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">cout </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">wri=
te_all</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">a</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #800;" class=3D"styled-by-prettify">// Output: "abc"</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br><br>std</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">cout </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">"{ "</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">write_a=
ll</span><span style=3D"color: #660;" class=3D"styled-by-prettify">({</span=
><span style=3D"color: #066;" class=3D"styled-by-prettify">1</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066=
;" class=3D"styled-by-prettify">2</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-pret=
tify">3</span><span style=3D"color: #660;" class=3D"styled-by-prettify">},<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #080;" class=3D"styled-by-prettify">", "</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=3D"=
styled-by-prettify">" }"</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br></span><span style=3D"color: #800;" class=3D"styled-by-prettify">/=
/ Output: "{ 1, 2, 3 }"</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br></span></div></code></div><br>You can capture the range ou=
tput object returned by write_all(), and query it for information about the=
 last write:<br><br><div class=3D"prettyprint" style=3D"background-color: r=
gb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; b=
order-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div =
class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> p </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">write_all</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">r</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">cout </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> p</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">if</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">p</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">.</span><span style=3D"color: #008;" class=3D"=
styled-by-prettify">next</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">!=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
r</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">end</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">())</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br>&nbsp; std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">cerr </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" class=
=3D"styled-by-prettify">"Error writing r. Only "</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> p</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">count </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">" val=
ues written."</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></=
span></div></code></div><br>And, of course, formatting is properly handled:=
<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250,=
 250); border-color: rgb(187, 187, 187); border-style: solid; border-width:=
 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"sub=
prettyprint"><code class=3D"prettyprint"><span style=3D"color: #000;" class=
=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">cout </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&lt;&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #080;" class=3D"styled-by-prettify">"{ "</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> &lt;&lt; set=
w(5) &lt;&lt; setfill('_') </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">&lt;&lt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">std</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">write_all</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>({</span><span style=3D"color: #066;" class=3D"styled-by-prettify">1</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #066;" class=3D"styled-by-prettify">2</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"style=
d-by-prettify">3</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">},</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #080;" class=3D"styled-by-prettify">", "</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">&lt;&lt;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #080;" =
class=3D"styled-by-prettify">" }"</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br></span><span style=3D"color: #800;" class=3D"styled-by-p=
rettify">// Output: "{ ____1, </span></code><code class=3D"prettyprint"><sp=
an style=3D"color: #800;" class=3D"styled-by-prettify"><code class=3D"prett=
yprint"><code class=3D"prettyprint"><span style=3D"color: #800;" class=3D"s=
tyled-by-prettify">____</span></code></code>2, </span></code><code class=3D=
"prettyprint"><span style=3D"color: #800;" class=3D"styled-by-prettify"><co=
de class=3D"prettyprint"><code class=3D"prettyprint"><span style=3D"color: =
#800;" class=3D"styled-by-prettify">____</span></code></code>3 }"</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span></code><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify"></span></div></code=
></div><br>Input consists of 8 functions. There is a generic input function=
 - input() - that can be customized via a traits class for any kind of inpu=
t behaviour and filtering. Then there are 4 ready-made input behaviour func=
tions: overwrite, back insert, front insert, and general insert (the latter=
 3 come in 2 flavours - "read until you can't read anymore", and "stop afte=
r n successful reads"). Formatting and error querying works for input, too.=
<br><br>For more info, I put the documentation in the source package online=
: <a href=3D"http://cpp.indi.frih.net/rangeio/">http://cpp.indi.frih.net/ra=
ngeio/</a><br><br>Does anyone have any comments, questions, or suggestions =
for what I've got so far?<br></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_169_1695985880.1410878033173--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Thu, 18 Sep 2014 13:22:51 -0700 (PDT)
Raw View
------=_Part_146_93958380.1411071771816
Content-Type: text/plain; charset=UTF-8

I think write_all is a good functionality for the output case.

For input I have some comments:

- The "general" input() function with its behaviour class seems a bit
overworked and will require a lot of standards text. The gain from having
this function seems very small.

- It would be better if the destination was called 'container' instead of
'range' for those functions where what is normally called a range doesn't
work, i.e. all but overwrite.

- I would like an easier way to subdivide the input stream's data into
elements than having to write your own behaviour class. Maybe an extra
string parameter just as for write_all.

I like the names of the input functions though.

Den tisdagen den 16:e september 2014 kl. 16:33:53 UTC+2 skrev Mark A. Gibbs:
>
> I have redesigned the sample implementation and added a bunch of new
> features.
>
> The output portion is a single function - write_all() - overloaded for
> optional delimiters:
>
> auto const a = std::array<char, 3>{'a', 'b', 'c'};
> std::cout << std::write_all(a);
> // Output: "abc"
>
> std::cout << "{ " << std::write_all({1, 2, 3}, ", ") << " }";
> // Output: "{ 1, 2, 3 }"
>
> You can capture the range output object returned by write_all(), and query
> it for information about the last write:
>
> auto p = std::write_all(r);
> std::cout << p;
>
> if (p.next != r.end())
>   std::cerr << "Error writing r. Only " << p.count << " values written.";
>
> And, of course, formatting is properly handled:
>
> std::cout << "{ " << setw(5) << setfill('_') <<
>              std::write_all({1, 2, 3}, ", ") << " }";
> // Output: "{ ____1, ____2, ____3 }"
>
> Input consists of 8 functions. There is a generic input function - input()
> - that can be customized via a traits class for any kind of input behaviour
> and filtering. Then there are 4 ready-made input behaviour functions:
> overwrite, back insert, front insert, and general insert (the latter 3 come
> in 2 flavours - "read until you can't read anymore", and "stop after n
> successful reads"). Formatting and error querying works for input, too.
>
> For more info, I put the documentation in the source package online:
> http://cpp.indi.frih.net/rangeio/
>
> Does anyone have any comments, questions, or suggestions for what I've got
> so far?
>

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_146_93958380.1411071771816
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I think write_all is a good functionality for the output c=
ase.<div><br></div><div>For input I have some comments:</div><div><br></div=
><div>- The "general" input() function with its behaviour class seems a bit=
 overworked and will require a lot of standards text. The gain from having =
this function seems very small.</div><div><br></div><div>- It would be bett=
er if the destination was called 'container' instead of 'range' for those f=
unctions where what is normally called a range doesn't work, i.e. all but o=
verwrite.</div><div><br></div><div>- I would like an easier way to subdivid=
e the input stream's data into elements than having to write your own behav=
iour class. Maybe an extra string parameter just as for write_all.</div><di=
v><br>I like the names of the input functions though.<br><br>Den tisdagen d=
en 16:e september 2014 kl. 16:33:53 UTC+2 skrev Mark A. Gibbs:<blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
 #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">I have redesigned the samp=
le implementation and added a bunch of new features.<br><br>The output port=
ion is a single function - write_all() - overloaded for optional delimiters=
:<br><br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(1=
87,187,187);border-style:solid;border-width:1px;word-wrap:break-word"><code=
><div><span style=3D"color:#008">auto</span><span style=3D"color:#000"> </s=
pan><span style=3D"color:#008">const</span><span style=3D"color:#000"> a </=
span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> std</=
span><span style=3D"color:#660">::</span><span style=3D"color:#000">array</=
span><span style=3D"color:#660">&lt;</span><span style=3D"color:#008">char<=
/span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span=
><span style=3D"color:#066">3</span><span style=3D"color:#660">&gt;{</span>=
<span style=3D"color:#080">'a'</span><span style=3D"color:#660">,</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#080">'b'</span><span =
style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#080">'c'</span><span style=3D"color:#660">};</span><span style=
=3D"color:#000"><br>std</span><span style=3D"color:#660">::</span><span sty=
le=3D"color:#000">cout </span><span style=3D"color:#660">&lt;&lt;</span><sp=
an style=3D"color:#000"> std</span><span style=3D"color:#660">::</span><spa=
n style=3D"color:#000">write_all</span><span style=3D"color:#660">(</span><=
span style=3D"color:#000">a</span><span style=3D"color:#660">);</span><span=
 style=3D"color:#000"><br></span><span style=3D"color:#800">// Output: "abc=
"</span><span style=3D"color:#000"><br><br>std</span><span style=3D"color:#=
660">::</span><span style=3D"color:#000">cout </span><span style=3D"color:#=
660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"color=
:#080">"{ "</span><span style=3D"color:#000"> </span><span style=3D"color:#=
660">&lt;&lt;</span><span style=3D"color:#000"> std</span><span style=3D"co=
lor:#660">::</span><span style=3D"color:#000">write_all</span><span style=
=3D"color:#660">({</span><span style=3D"color:#066">1</span><span style=3D"=
color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color=
:#066">2</span><span style=3D"color:#660">,</span><span style=3D"color:#000=
"> </span><span style=3D"color:#066">3</span><span style=3D"color:#660">},<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#080">", "</s=
pan><span style=3D"color:#660">)</span><span style=3D"color:#000"> </span><=
span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:#000"> </span=
><span style=3D"color:#080">" }"</span><span style=3D"color:#660">;</span><=
span style=3D"color:#000"><br></span><span style=3D"color:#800">// Output: =
"{ 1, 2, 3 }"</span><span style=3D"color:#000"><br></span></div></code></di=
v><br>You can capture the range output object returned by write_all(), and =
query it for information about the last write:<br><br><div style=3D"backgro=
und-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid=
;border-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#00=
8">auto</span><span style=3D"color:#000"> p </span><span style=3D"color:#66=
0">=3D</span><span style=3D"color:#000"> std</span><span style=3D"color:#66=
0">::</span><span style=3D"color:#000">write_all</span><span style=3D"color=
:#660">(</span><span style=3D"color:#000">r</span><span style=3D"color:#660=
">);</span><span style=3D"color:#000"><br>std</span><span style=3D"color:#6=
60">::</span><span style=3D"color:#000">cout </span><span style=3D"color:#6=
60">&lt;&lt;</span><span style=3D"color:#000"> p</span><span style=3D"color=
:#660">;</span><span style=3D"color:#000"><br><br></span><span style=3D"col=
or:#008">if</span><span style=3D"color:#000"> </span><span style=3D"color:#=
660">(</span><span style=3D"color:#000">p</span><span style=3D"color:#660">=
..</span><span style=3D"color:#008">next</span><span style=3D"color:#000"> <=
/span><span style=3D"color:#660">!=3D</span><span style=3D"color:#000"> r</=
span><span style=3D"color:#660">.</span><span style=3D"color:#008">end</spa=
n><span style=3D"color:#660">())</span><span style=3D"color:#000"><br>&nbsp=
; std</span><span style=3D"color:#660">::</span><span style=3D"color:#000">=
cerr </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"color:=
#000"> </span><span style=3D"color:#080">"Error writing r. Only "</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&lt;</span><=
span style=3D"color:#000"> p</span><span style=3D"color:#660">.</span><span=
 style=3D"color:#000">count </span><span style=3D"color:#660">&lt;&lt;</spa=
n><span style=3D"color:#000"> </span><span style=3D"color:#080">" values wr=
itten."</span><span style=3D"color:#660">;</span><span style=3D"color:#000"=
><br></span></div></code></div><br>And, of course, formatting is properly h=
andled:<br><br><div style=3D"background-color:rgb(250,250,250);border-color=
:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:break-word"=
><code><div><code><span style=3D"color:#000">std</span><span style=3D"color=
:#660">::</span><span style=3D"color:#000">cout </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#080">"{ "</span><span style=3D"color:#000"> &lt;&lt; setw(5) &lt;&lt; s=
etfill('_') </span><span style=3D"color:#660">&lt;&lt;<br>&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style=
=3D"color:#000">std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#000">write_all</span><span style=3D"color:#660">({</span><span s=
tyle=3D"color:#066">1</span><span style=3D"color:#660">,</span><span style=
=3D"color:#000"> </span><span style=3D"color:#066">2</span><span style=3D"c=
olor:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:=
#066">3</span><span style=3D"color:#660">},</span><span style=3D"color:#000=
"> </span><span style=3D"color:#080">", "</span><span style=3D"color:#660">=
)</span><span style=3D"color:#000"> </span><span style=3D"color:#660">&lt;&=
lt;</span><span style=3D"color:#000"> </span><span style=3D"color:#080">" }=
"</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br><=
/span><span style=3D"color:#800">// Output: "{ ____1, </span></code><code><=
span style=3D"color:#800"><code><code><span style=3D"color:#800">____</span=
></code></code>2, </span></code><code><span style=3D"color:#800"><code><cod=
e><span style=3D"color:#800">____</span></code></code>3 }"</span><span styl=
e=3D"color:#000"><br></span></code><span style=3D"color:#660"></span></div>=
</code></div><br>Input consists of 8 functions. There is a generic input fu=
nction - input() - that can be customized via a traits class for any kind o=
f input behaviour and filtering. Then there are 4 ready-made input behaviou=
r functions: overwrite, back insert, front insert, and general insert (the =
latter 3 come in 2 flavours - "read until you can't read anymore", and "sto=
p after n successful reads"). Formatting and error querying works for input=
, too.<br><br>For more info, I put the documentation in the source package =
online: <a href=3D"http://cpp.indi.frih.net/rangeio/" target=3D"_blank" onm=
ousedown=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fcpp.ind=
i.frih.net%2Frangeio%2F\46sa\75D\46sntz\0751\46usg\75AFQjCNEAbZkFXTiEsa5zRW=
C3zW50x8G27A';return true;" onclick=3D"this.href=3D'http://www.google.com/u=
rl?q\75http%3A%2F%2Fcpp.indi.frih.net%2Frangeio%2F\46sa\75D\46sntz\0751\46u=
sg\75AFQjCNEAbZkFXTiEsa5zRWC3zW50x8G27A';return true;">http://cpp.indi.frih=
..net/<wbr>rangeio/</a><br><br>Does anyone have any comments, questions, or =
suggestions for what I've got so far?<br></div></blockquote></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_146_93958380.1411071771816--

.


Author: "Mark A. Gibbs" <indi.in.the.wired@gmail.com>
Date: Sat, 20 Sep 2014 06:46:56 -0700 (PDT)
Raw View
------=_Part_3252_2142398467.1411220816832
Content-Type: text/plain; charset=UTF-8

On Thursday, 18 September 2014 16:22:51 UTC-4, Bengt Gustafsson wrote:
>
> - I would like an easier way to subdivide the input stream's data into
> elements than having to write your own behaviour class. Maybe an extra
> string parameter just as for write_all.
>

How would that work?

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_3252_2142398467.1411220816832
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Thursday, 18 September 2014 16:22:51 UTC-4, Bengt Gusta=
fsson  wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">=
- I would like an easier way to subdivide the input stream's data into elem=
ents than having to write your own behaviour class. Maybe an extra string p=
arameter just as for write_all.</div></blockquote><div><br>How would that w=
ork?</div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_3252_2142398467.1411220816832--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sun, 21 Sep 2014 08:17:56 -0700 (PDT)
Raw View
------=_Part_3531_40242626.1411312676751
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

I was thinking that this could be unifies=20
with http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3510.html,=20
the split() proposal, and in particular its Delimiter concept.

However, I now note two differences that makes this idea less promising:

- we don't want to require a particular look ahead into the input stream.
- the input functions convert data from string to some other type,=20
typically one of the numeric types.

This said, I still think we want something more than just "consume as many=
=20
characters as possible per element and then skip all whitespace between=20
each". This precludes reading simple things such as a comma separated list=
=20
of numbers.

So at the least a delimiter which is a string that must exist (possibly=20
surrounded on one or both ends by whitespace) between elements. This also=
=20
provides a good level of symmetry to write_all for simple cases: If you=20
provide the same delimiter string to input() that you used for write_all it=
=20
will be able to read your data file back.

There are of course lots of other cases with trickier rules for when an=20
element ends and the next one starts. This is when a Delimiter object would=
=20
come in handy.
To design a Delimiter concept for use with an istream is however less than=
=20
trivial as the succeding data conversion will need the data again and it=20
would not be allowed to pre-read into a buffer before calling the Delimiter=
=20
functionality as that
could cause failures which are not called for (for instance when reading 5=
=20
ints from a socket you can't read n bytes as they may never arrive even=20
given that the stream is not at eof or failed).

Another delimiter related issue is that if you by default just use=20
operator>>(stream, T) you will have weak string support as you can't avoid=
=20
stopping at white space. Splitting a file into lines is such a common=20
operation that I think it must be supported.

Maybe, given that this is supposedly going into the std library an=20
alternate approach to investigate would be to augment the istream API with=
=20
some delimiter functionality. For instance a manipulator 'std::linewise'=20
could be devised to tell an istream that >> string should give me the next=
=20
full line. This would be rather handy even outside the scope of the input()=
=20
function. Similarly a delimiter(',') manipulator could be used to read=20
comma separated numbers from the stream. On the other hand we already have=
=20
a problem with the muddled role of istream carrying around a lot of state=
=20
which encourages error prone programming practices like "leaving cin in the=
=20
last state you used". I saw another proposal to add push() and pop()=20
manipulators to iostream. This however seems like something of a band aid=
=20
solution to me.

When I looked at your input API with its four different "modes" I noted=20
that front_insert and insert are likely to have a performance problem as=20
they have to resize the container for each
element read. It could be better to exclude these versions and instead=20
provide a basic function which returns a vector (or unspecified container)=
=20
which can then be inserted in one go into the receiving
container:

template<typename T> vector<T> getvalues(istream& src, Delimiter& delim =3D=
=20
std_delimiter);

use:

my_vector.insert(next(my_vector.begin(), 3), getvalues<int>(cin));

after all this is much less common than the push-back or overwrite cases.

Another issue relates to associative containers (sets) where "insert" would=
=20
be the correct name for the function but the iterator parameter is not=20
applicable (as the position of each element depends on its value). Maybe=20
this can be fixed by overloading with enable_if or concepts
so that when the container is associative you don't give the position.

Here's a simple idea for a Delimiter concept:

concept Delimiter {
    size_t run(char_t next);
};

run() returns 0 until the delimiter is seen, at which point it returns > 0,=
=20
where the number denotes the character count which is the delimiter and is=
=20
not to be part of the element's text representation. It should be allowed=
=20
for the run() function to return a number larger
than the number of chars it has been presented in order to skip an entire=
=20
element from being processed.

This is trivial to use for implementing one character delimiters:

size_t ends(char next) { return size_t(next =3D=3D ','); }

But for more complex cases it would of course be advantageous to be able to=
=20
see the entire string so far. Typically the input() function would have to=
=20
store this in a buffer anyway for the upcoming conversion which make an API=
=20
like this more attractive:

concept Delimiter {
    size_t run(char_t *buffer, size_t count);
};

run() would be called with the same buffer but increasing count until it=20
returns a nonzero number denoting where the value preceeding the delimiter=
=20
ends. The drawback of this idea is that it forces the input()=20
implementation to buffer the text for the benefit of the Delimiter object,=
=20
while it may not need to do this=20
for its own purposes.


Den l=C3=B6rdagen den 20:e september 2014 kl. 15:46:56 UTC+2 skrev Mark A. =
Gibbs:
>
> On Thursday, 18 September 2014 16:22:51 UTC-4, Bengt Gustafsson wrote:
>>
>> - I would like an easier way to subdivide the input stream's data into=
=20
>> elements than having to write your own behaviour class. Maybe an extra=
=20
>> string parameter just as for write_all.
>>
>
> How would that work?
>

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

------=_Part_3531_40242626.1411312676751
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I was thinking that this could be unifies with&nbsp;http:/=
/www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3510.html, the split() p=
roposal, and in particular its Delimiter concept.<div><br></div><div>Howeve=
r, I now note two differences that makes this idea less promising:</div><di=
v><br></div><div>- we don't want to require a particular look ahead into th=
e input stream.</div><div>- the input functions convert data from string to=
 some other type, typically one of the numeric types.</div><div><br></div><=
div>This said, I still think we want something more than just "consume as m=
any characters as possible per element and then skip all whitespace between=
 each". This precludes reading simple things such as a comma separated list=
 of numbers.</div><div><br></div><div>So at the least a delimiter which is =
a string that must exist (possibly surrounded on one or both ends by whites=
pace) between elements. This also provides a good level of symmetry to writ=
e_all for simple cases: If you provide the same delimiter string to input()=
 that you used for write_all it will be able to read your data file back.</=
div><div><br></div><div>There are of course lots of other cases with tricki=
er rules for when an element ends and the next one starts. This is when a D=
elimiter object would come in handy.</div><div>To design a Delimiter concep=
t for use with an istream is however less than trivial as the succeding dat=
a conversion will need the data again and it would not be allowed to pre-re=
ad into a buffer before calling the Delimiter functionality as that</div><d=
iv>could cause failures which are not called for (for instance when reading=
 5 ints from a socket you can't read n bytes as they may never arrive even =
given that the stream is not at eof or failed).</div><div><br></div><div>An=
other delimiter related issue is that if you by default just use operator&g=
t;&gt;(stream, T) you will have weak string support as you can't avoid stop=
ping at white space. Splitting a file into lines is such a common operation=
 that I think it must be supported.</div><div><br></div><div>Maybe, given t=
hat this is supposedly going into the std library an alternate approach to =
investigate would be to augment the istream API with some delimiter functio=
nality. For instance a manipulator 'std::linewise' could be devised to tell=
 an istream that &gt;&gt; string should give me the next full line. This wo=
uld be rather handy even outside the scope of the input() function. Similar=
ly a delimiter(',') manipulator could be used to read comma separated numbe=
rs from the stream. On the other hand we already have a problem with the mu=
ddled role of istream carrying around a lot of state which encourages error=
 prone programming practices like "leaving cin in the last state you used".=
 I saw another proposal to add push() and pop() manipulators to iostream. T=
his however seems like something of a band aid solution to me.</div><div><b=
r></div><div>When I looked at your input API with its four different "modes=
" I noted that front_insert and insert are likely to have a performance pro=
blem as they have to resize the container for each</div><div>element read. =
It could be better to exclude these versions and instead provide a basic fu=
nction which returns a vector (or unspecified container) which can then be =
inserted in one go into the receiving</div><div>container:</div><div><br></=
div><div>template&lt;typename T&gt; vector&lt;T&gt; getvalues(istream&amp; =
src, Delimiter&amp; delim =3D std_delimiter);</div><div><br></div><div>use:=
</div><div><br></div><div>my_vector.insert(next(my_vector.begin(), 3), getv=
alues&lt;int&gt;(cin));</div><div><br></div><div>after all this is much les=
s common than the push-back or overwrite cases.</div><div><br></div><div>An=
other issue relates to associative containers (sets) where "insert" would b=
e the correct name for the function but the iterator parameter is not appli=
cable (as the position of each element depends on its value). Maybe this ca=
n be fixed by overloading with enable_if or concepts</div><div>so that when=
 the container is associative you don't give the position.</div><div><br></=
div><div>Here's a simple idea for a Delimiter concept:</div><div><br></div>=
<div>concept Delimiter {</div><div>&nbsp; &nbsp; size_t run(char_t next);</=
div><div>};</div><div><br></div><div>run() returns 0 until the delimiter is=
 seen, at which point it returns &gt; 0, where the number denotes the chara=
cter count which is the delimiter and is not to be part of the element's te=
xt representation. It should be allowed for the run() function to return a =
number larger</div><div>than the number of chars it has been presented in o=
rder to skip an entire element from being processed.</div><div><br></div><d=
iv>This is trivial to use for implementing one character delimiters:</div><=
div><br></div><div>size_t ends(char next) { return size_t(next =3D=3D ',');=
 }</div><div><br></div><div>But for more complex cases it would of course b=
e advantageous to be able to see the entire string so far. Typically the in=
put() function would have to store this in a buffer anyway for the upcoming=
 conversion which make an API like this more attractive:</div><div><br></di=
v><div>concept Delimiter {</div><div>&nbsp; &nbsp; size_t run(char_t *buffe=
r, size_t count);</div><div>};</div><div><br></div><div>run() would be call=
ed with the same buffer but increasing count until it returns a nonzero num=
ber denoting where the value preceeding the delimiter ends. The drawback of=
 this idea is that it forces the input() implementation to buffer the text =
for the benefit of the Delimiter object, while it may not need to do this&n=
bsp;</div><div>for its own purposes.</div><div><br></div><div><br>Den l=C3=
=B6rdagen den 20:e september 2014 kl. 15:46:56 UTC+2 skrev Mark A. Gibbs:<b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On Thursday, 18=
 September 2014 16:22:51 UTC-4, Bengt Gustafsson  wrote:<blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr">- I would like an easier way to sub=
divide the input stream's data into elements than having to write your own =
behaviour class. Maybe an extra string parameter just as for write_all.</di=
v></blockquote><div><br>How would that work?</div></div></blockquote></div>=
</div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_3531_40242626.1411312676751--

.