    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: C++ Pipes</title>
        <link>https://members.accu.org/index.php/journals/2702</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>


        <h2>Journal Articles</h2>


<div class="xar-mod-head"><span class="xar-mod-title">Overload Journal #153 - October 2019 + Design of applications and programs</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c403/">o153</a>
                    (6)
<br />

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c67/">Design</a>
                    (236)
<br />

                                            <a href="https://members.accu.org/index.php/journals/c403-67/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/journals/c403+67/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;C++ Pipes</h1>
<p><strong>Author:</strong>&nbsp;Bob Schmidt</p>
<p>
<strong>Date:</strong> 02 October 2019 19:14:28 +01:00 or Wed, 02 October 2019 19:14:28 +01:00</p>
<p><strong>Summary:</strong>&nbsp;Expressive code can make life easier. Jonathan Boccara demonstrates fluent pipelines for collections in C++.</p>
<p><strong>Body:</strong>&nbsp;<p>Pipes are small components for writing expressive code when working on collections. Pipes chain together into a pipeline that receives data from a source, operates on that data, and sends the results to a destination.</p>

<p>This is a header-only library, implemented in C++14.</p>

<p>The library is under development and subject to change. Contributions are welcome. You can also log an issue if you have a wish for enhancement or if you spot a bug.</p>

<h2>A first example</h2>

<p>Here is a simple example of a pipeline made of two pipes: <code>transform</code> and <code>filter</code>:</p>

<pre class="programlisting">
  auto const source = std::vector&lt;int&gt;{0, 1, 2, 3,
    4, 5, 6, 7, 8, 9};
  auto destination = std::vector&lt;int&gt;{};
  source &gt;&gt;= pipes::filter([](int i)
             { return i % 2 == 0; })
         &gt;&gt;= pipes::transform([](int i)
             { return i * 2; })
         &gt;&gt;= pipes::push_back(destination);
  // destination contains {0, 4, 8, 12, 16};</pre>

<h3>Whatâ€™s going on here</h3>
<ul>
	<li>Each element of <code>source</code> is sent to <code>filter</code>.</li>
	
	<li>Every time <code>filter</code> receives a piece of data, it sends its to the next pipe (here, <code>transform</code>) only if that piece of data satisfies <code>filter</code>â€™s predicate.</li>
	
	<li><code>transform</code> then applies its function on the data its gets and sends the result to the
	next pipe (here, <code>pipes::push_back</code>).</li>
	
	<li><code>pipes::push_back</code> <code>push_back</code>s the data it receives to its <code>vector</code> (here, <code>destination</code>).</li>
</ul>

<h2>A second example</h2>

<p>Here is a more elaborate example with a pipeline that branches out in several directions:</p>

<pre class="programlisting">
  A &gt;&gt;= pipes::transform(f)
    &gt;&gt;= pipes::filter(p)
    &gt;&gt;= pipes::unzip(pipes::push_back(B),
        pipes::demux(pipes::push_back(C),
        pipes::filter(q) &gt;&gt;= pipes::push_back(D),
        pipes::filter(r) &gt;&gt;= pipes::push_back(E));</pre>
		
<p>Here, <code>unzip</code> takes the <code>std::pair</code>s or <code>std::tuple</code>s it receives and breaks them down into individual elements. It sends each element to the pipes it takes (here <code>pipes::push_back</code> and <code>demux</code>). </p>

<p><code>demux</code> takes any number of pipes and sends the data it receives to each of them.</p>

<p>Since data circulates through pipes, real life pipes and plumbing provide a nice analogy (which gave its names to the library). For example, the above pipeline can be graphically represented like Figure 1.</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol153/Boccara/Boccara-01.png" /></td>
	</tr>
	<tr>
		<td class="title">Figure 1</td>
	</tr>
</table>

<h2>Doesnâ€™t it look like ranges?</h2>

<p>Pipes sort of look like ranges adaptors from afar, but those two libraries have very different designs.</p>

<p>Range views are about adapting ranges with view layers, and reading through those layers in lazy mode. Pipes are about sending pieces of data as they come along in a collection through a pipeline, and letting them land in a destination.</p>

<p>Ranges and pipes have overlapping components such as <code>transform</code> and <code>filter</code>. But pipes do things like ranges canâ€™t do, such as <code>pipes::mux</code>, <code>pipes::demux</code> and <code>pipes:unzip</code>, and ranges do things that pipes canâ€™t do, like infinite ranges.</p>

<p>It is possible to use ranges and pipes in the same expression though:</p>

<pre class="programlisting">
  ranges::view::zip(dadChromosome, momChromosome)
    &gt;&gt;= pipes::transform(crossover) // crossover

        // takes and returns a tuple of 2 elements
    &gt;&gt;= pipes::unzip(pipes::push_back
          (gameteChromosome1),
        pipes::push_back(gameteChromosome2));</pre>


<h2>Operating on several collections</h2>

<p>The pipes library allows to manipulate several collections at the same time, with the <code>pipes::mux</code> helper. Note that contrary to <code>range::view::zip</code>, <code>pipes::mux</code> doesnâ€™t require to use tuples.</p>

<pre class="programlisting">
  auto const input1 = std::vector&lt;int&gt;{1, 2, 3, 4,
    5};
  auto const input2 = std::vector&lt;int&gt;{10, 20, 30,
    40, 50};
  auto results = std::vector&lt;int&gt;{};

  pipes::mux(input1, input2) 
    &gt;&gt;= pipes::filter   ([](int a, int b)
        { return a + b &lt; 40; })
    &gt;&gt;= pipes::transform([](int a, int b) 
        { return a * b; })
    &gt;&gt;= pipes::push_back(results);</pre>
	
<p>    // results contains {10, 40, 90}</p>

<h3>Operating on all the possible combinations between several collections</h3>

<p><code>pipes::cartesian_product</code> takes any number of collections, and generates all the possible combinations between the elements of those collections. It sends each combination successively to the next pipe after it.</p>

<p>Like <code>pipes::mux</code>, <code>pipes::cartesian_product</code> doesnâ€™t use tuples but sends the values directly to the next pipe:</p>

<pre class="programlisting">
  auto const inputs1 = std::vector&lt;int&gt;{1, 2, 3};
  auto const inputs2 
    = std::vector&lt;std::string&gt;{&quot;up&quot;, &quot;down&quot;};
  auto results = std::vector&lt;std::string&gt;{};

  pipes::cartesian_product(inputs1, inputs2)
    &gt;&gt;= pipes::transform([](int i, 
        std::string const&amp; s)
        { return std::to_string(i) + '-' + s; })
    &gt;&gt;= pipes::push_back(results);
  // results contains {&quot;1-up&quot;, &quot;1-down&quot;, &quot;2-up&quot;,
  // &quot;2-down&quot;, &quot;3-up&quot;, &quot;3-down&quot;}</pre>

<h2>End pipes</h2>

<p>This library also provides end pipes, which are components that send data to a collection in an elaborate way. For example, the <code>map_aggregate</code> pipe receives <code>std::pair&lt;Key, Value&gt;</code>s and adds them to a map with the following rule:</p>

<ul>
	<li>if its key is not already in the map, insert the incoming pair in the map,</li>
	
	<li>otherwise, aggregate the value of the incoming pair with the existing one in the map.</li>
</ul>

<p>Example:</p>

<pre class="programlisting">
  std::map&lt;int, std::string&gt; entries = { {1, &quot;a&quot;},
    {2, &quot;b&quot;}, {3, &quot;c&quot;}, {4, &quot;d&quot;} };
  std::map&lt;int, std::string&gt; entries2 = { {2, &quot;b&quot;},
    {3, &quot;c&quot;}, {4, &quot;d&quot;}, {5, &quot;e&quot;} };
  std::map&lt;int, std::string&gt; results;
  // results is empty

  entries &gt;&gt;= pipes::map_aggregator(results,
    concatenateStrings);
  // the elements of entries have been inserted into
  // results

  entries2 &gt;&gt;= pipes::map_aggregator(results,
    concatenateStrings);
  // the new elements of entries2 have been inserter
  // into results, the existing ones have been
  // concatenated with the new values 
  // results contains { {1, &quot;a&quot;}, {2, &quot;bb&quot;}, 
  // {3, &quot;cc&quot;}, {4, &quot;dd&quot;}, {5, &quot;e&quot;} }</pre>
  
<p>All components are located in the namespace <code>pipes</code>.</p>

<h2>Easy integration with STL algorithms</h2>

<p>All pipes can be used as output iterators of STL algorithms (see Figure 2):</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol153/Boccara/Boccara-02.png" /></td>
	</tr>
	<tr>
		<td class="title">Figure 2</td>
	</tr>
</table>


<pre class="programlisting">
  std::set_difference(begin(setA), end(setA),
                      begin(setB), end(setB),
    transform(f) &gt;&gt;= filter(p) 
      &gt;&gt;= map_aggregator(results, addValues));</pre>

<h2>Streams support</h2>

<p>The contents of an input stream can be sent to a pipe by using <code>read_in_stream</code>. The end pipe <code>to_out_stream</code> sends data to an output stream.</p>

<p>The following example reads strings from the standard input, transforms them to upper case, and sends them to the standard output:</p>

<pre class="programlisting">
  std::cin &gt;&gt;= pipes::read_in_stream&lt;std::string&gt;{}
           &gt;&gt;= pipes::transform(toUpper)
           &gt;&gt;= pipes::to_out_stream(std::cout);</pre>

<h2>General pipes</h2>

<h3>demux</h3>

<p><img src="/content/images/journals/ol153/Boccara/Boccara-03.png" /></p>

<p><code>demux</code> is a pipe that takes any number of pipes, and sends a copy of the values it receives to each of those pipes.</p>

<pre class="programlisting">
  std::vector&lt;int&gt; input = {1, 2, 3,
    4, 5};
  std::vector&lt;int&gt; results1;
  std::vector&lt;int&gt; results2;
  std::vector&lt;int&gt; results3;

  input &gt;&gt;= pipes::demux(
    pipes::push_back {results1),
    pipes::push_back(results2),
    pipes::push_back(results3));
  // results1 contains {1, 2, 3, 4, 5}
  // results2 contains {1, 2, 3, 4, 5}
  // results3 contains {1, 2, 3, 4, 5}</pre>

<h3>dev_null</h3>

<p><code>dev_null</code> is a pipe that doesnâ€™t do anything with the value it receives. It is useful for selecting only some data coming out of an algorithm that has several outputs. An example of such algorithm is <code>set_segregate</code> [<a href="#[Boccara]">Boccara</a>]:</p>

<pre class="programlisting">
  std::set&lt;int&gt; setA = {1, 2, 3, 4, 5};
  std::set&lt;int&gt; setB = {3, 4, 5, 6, 7};
  std::vector&lt;int&gt; inAOnly;
  std::vector&lt;int&gt; inBoth;
  sets::set_seggregate(setA, setB,
                       pipes::push_back(inAOnly),
                       pipes::push_back(inBoth),
                       dev_null{});
  // inAOnly contains {1, 2}
  // inBoth contains {3, 4, 5}</pre>

<h3>drop</h3>

<p><code>drop</code> is a pipe that ignores the first N incoming values, and sends on the values after them to the next pipe:</p>

<pre class="programlisting">
  auto const input = std::vector&lt;int&gt;{ 1, 2, 3, 4,
     5, 6, 7, 8, 9, 10};
  auto result = std::vector&lt;int&gt;{};
  input &gt;&gt;= pipes::drop(5)
        &gt;&gt;= pipes::push_back(result);
  // result contains { 6, 7, 8, 9, 10 }</pre>

<h3>drop_while</h3>

<p><code>drop</code> is a pipe that ignores the incoming values until they stop satisfying a predicate, and sends on the values after them to the next pipe:</p>

<pre class="programlisting">
  auto const input = std::vector&lt;int&gt;{ 1, 2, 3, 4,
    5, 6, 7, 8, 9, 10};
  auto result = std::vector&lt;int&gt;{};
  input &gt;&gt;= pipes::drop_while([](int i)
    { return i != 6; })
    &gt;&gt;= pipes::push_back(result);
  // result contains { 6, 7, 8, 9, 10 }</pre>

<h3>filter</h3>

<p><img src="/content/images/journals/ol153/Boccara/Boccara-04.png" /></p>

<p><code>filter</code> is a pipe that takes a predicate <code>p</code> and, when it receives a value <code>x</code>, sends the result on to the next pipe if <code>p(x)</code> is <code>true</code>.</p>

<pre class="programlisting">
  std::vector&lt;int&gt; input = {1, 2, 3, 4, 5, 6, 7, 8,
    9, 10};
  std::vector&lt;int&gt; results;
  input &gt;&gt;= pipes::filter([](int i)
    { return i % 2 == 0; })
    &gt;&gt;= pipes::push_back(results);
  // results contains {2, 4, 6, 8, 10}</pre>

<h3>join</h3>

<p>The <code>join</code> pipe receives collection and sends each element of each of those collections to the next pipe:</p>

<pre class="programlisting">
  auto const input = std::vector&lt;std::vector&lt;int&gt;&gt;{
    {1, 2}, {3, 4}, {5, 6} };
  auto results = std::vector&lt;int&gt;{};
  input &gt;&gt;= pipes::join 
        &gt;&gt;= pipes::push_back(results);
  // results contain {1, 2, 3, 4, 5, 6}</pre>

<h3>partition</h3>

<p><img src="/content/images/journals/ol153/Boccara/Boccara-05.png" /></p>

<p><code>partition</code> is a pipe that takes a predicate <code>p</code> and two other pipes. When it receives a value <code>x</code>, sends the result on to the first pipe if <code>p(x) </code>is <code>true</code>, and to the second pipe if <code>p(x)</code> is <code>false</code>.</p>

<pre class="programlisting">
  std::vector&lt;int&gt; input = {1, 2, 3,
    4, 5, 6, 7, 8, 9, 10};
  std::vector&lt;int&gt; evens;
  std::vector&lt;int&gt; odds;
  input &gt;&gt;= pipes::partition([](int n)
      { return n % 2 == 0; },
    pipes::push_back(evens),
    pipes::push_back(odds));
  // evens contains {2, 4, 6, 8, 10}
  // odds contains {1, 3, 5, 7, 9}</pre>

<h3>read_in_stream</h3>

<p><code>read_in_stream</code> is a template pipe that reads from an input stream. The template parameter indicates what type of data to request from the stream:</p>

<pre class="programlisting">
  auto const input = std::string{&quot;1.1 2.2 3.3&quot;};
  std::istringstream(input) 
    &gt;&gt;= pipes::read_in_stream&lt;double&gt;{}
    &gt;&gt;= pipes::transform([](double d)
        { return d * 10; })
    &gt;&gt;= pipes::push_back(results);
  // results contain {11, 22, 33};</pre>

<h3>switch</h3>

<p><code>switch_</code> is a pipe that takes several <code>case_</code> branches. Each branch contains a predicate and a pipe. When it receives a value, it tries it successively on the predicates of each branch, and sends the value on to the pipe of the first branch where the predicate returns <code>true</code>. The <code>default_</code> branch is equivalent to one that takes a predicate that returns always <code>true</code>. Having a <code>default_</code> branch is not mandatory.</p>

<pre class="programlisting">
  std::vector&lt;int&gt; numbers = {1, 2, 3, 4, 5, 6, 7,
    8, 9, 10};
  std::vector&lt;int&gt; multiplesOf4;
  std::vector&lt;int&gt; multiplesOf3;
  std::vector&lt;int&gt; rest;
  numbers &gt;&gt;= pipes::switch_(
    pipes::case_([](int n){ return n % 4 == 0; }) 
      &gt;&gt;= pipes::push_back(multiplesOf4),
    pipes::case_([](int n){ return n % 3 == 0; })
      &gt;&gt;= pipes::push_back(multiplesOf3),
    pipes::default_ &gt;&gt;= pipes::push_back(rest) ));
  // multiplesOf4 contains {4, 8};
  // multiplesOf3 contains {3, 6, 9};
  // rest contains {1, 2, 5, 7, 10};</pre>

<h3>take</h3>

<p><code>take</code> takes a number <code>N</code> and sends to the next pipe the first <code>N</code> element that it receives. The elements after it are ignored:</p>

<pre class="programlisting">
  auto const input = std::vector&lt;int&gt;{1, 2, 3, 4,
    5, 6, 7, 8, 9, 10};
  auto result = std::vector&lt;int&gt;{};
  input &gt;&gt;= pipes::take(6)
        &gt;&gt;= pipes::push_back(result);
  // result contains {1, 2, 3, 4, 5, 6}</pre>

<h3>take_while</h3>

<p><code>take_while</code> takes a predicate and sends to the next pipe the first values it receives. It stops when one of them doesnâ€™t satisfy the predicate:</p>

<pre class="programlisting">
  auto const input = std::vector&lt;int&gt;{1, 2, 3, 4,
    5, 6, 7, 8, 9, 10};
  auto result = std::vector&lt;int&gt;{};
  input &gt;&gt;= pipes::take_while([](int i){ 
    return i != 7; })
    &gt;&gt;= pipes::push_back(result);
  // result contains {1, 2, 3, 4, 5, 6}</pre>

<h3>tee</h3>

<p><img src="/content/images/journals/ol153/Boccara/Boccara-06.png" /></p>

<p><code>tee</code> is a pipe that takes one other pipe, and sends a copy of the values it receives to each of these pipes before sending them on to the next pipe. Like the <code>tee</code> command on UNIX, this pipe is useful to take a peek at intermediary results.</p>

<pre class="programlisting">
  auto const inputs = std::vector&lt;int&gt;{1, 2, 3, 4,
    5, 6, 7, 8, 9, 10};
  auto intermediaryResults = std::vector&lt;int&gt;{};
  auto results = std::vector&lt;int&gt;{};
  inputs &gt;&gt;= pipes::tee(pipes::push_back
    (intermediaryResults))
    &gt;&gt;= pipes::push_back(results);
  // intermediaryResults contains {2, 4, 6, 8, 10,
  // 12, 14, 16, 18, 20}
  // results contains {12, 14, 16, 18, 20}</pre>

<h3>transform</h3>

<p><img src="/content/images/journals/ol153/Boccara/Boccara-07.png" /></p>

<p><code>transform</code> is a pipe that takes a function <code>f</code> and, when it receives a value, applies <code>f</code> on it and sends the result on to the next pipe.</p>

<pre class="programlisting">
  std::vector&lt;int&gt; input = {1, 2, 3, 4, 5};
  std::vector&lt;int&gt; results;
  input &gt;&gt;= pipes::transform([](int i) 
    { return i*2; })
    &gt;&gt;= pipes::push_back(results);
  // results contains {2, 4, 6, 8, 10}</pre>

<h3>unzip</h3>

<p><img src="/content/images/journals/ol153/Boccara/Boccara-08.png" /></p>

<p><code>unzip</code> is a pipe that takes N other pipes. When it receives a <code>std::pair</code> or <code>std::tuple</code> of size N (for <code>std::pair</code> N is 2), it sends each of its components to the corresponding output pipe:</p>

<pre class="programlisting">
  std::map&lt;int, std::string&gt; entries = { {1,
    &quot;one&quot;}, {2, &quot;two&quot;}, {3, &quot;three&quot;}, {4, &quot;four&quot;},
    {5, &quot;five&quot;} };
  std::vector&lt;int&gt; keys;
  std::vector&lt;std::string&gt; values;
  entries &gt;&gt;= pipes::unzip(pipes::push_back(keys),
    pipes::push_back(values)));
  // keys contains {1, 2, 3, 4, 5};
  // values contains {&quot;one&quot;, &quot;two&quot;, &quot;three&quot;, &quot;four&quot;,
  // &quot;five&quot;};</pre>

<h2>End pipes</h2>

<h3>custom</h3>

<p><code>custom</code> takes a function (or function object) that sends to the data it receives to that function. One of its usages is to give legacy code that does not use STL containers access to STL algorithms:</p>

<pre class="programlisting">
  std::vector&lt;int&gt; input = {1, 2, 3, 4, 5, 6, 7 ,8,
    9, 10};
  void legacyInsert(int number, DarkLegacyStructure
    const&amp; thing); // this function inserts into
                       // the old non-STL container
  DarkLegacyStructure legacyStructure = // ...

  std::copy(begin(input), end(input),
    custom([&amp;legacyStructure](int number){
    legacyInsert(number, legacyStructure); });</pre>
	
<p>Read the full story about making legacy code compatible with the STL on my blog [<a href="#[Boccara17a]">Boccara17a</a>].</p>

<p>Note that <code>custom</code> goes along with a helper function object, <code>do_</code>, that allows to perfom several actions sequentially on the output of the algorithm:</p>

<pre class="programlisting">
  std::copy(begin(input), end(input),
    pipes::custom(pipes::do_([&amp;](int i){
    results1.push_back(i*2);}).
    then_([&amp;](int i){ results2.push_back(i+1);}).
    then_([&amp;](int i){ results3.push_back(-i);})));</pre>

<h3>map_aggregator</h3>

<p><code>map_aggregator</code> provides the possibility to embark an aggregator function in the inserter iterator, so that new elements whose <em>key is already present in the map</em> can be merged with the existent (e.g. have their values added together).</p>

<pre class="programlisting">
  std::vector&lt;std::pair&lt;int, std::string&gt;&gt; entries
    = { {1, &quot;a&quot;}, {2, &quot;b&quot;}, {3, &quot;c&quot;}, {4, &quot;d&quot;} };
  std::vector&lt;std::pair&lt;int, std::string&gt;&gt; entries2
    = { {2, &quot;b&quot;}, {3, &quot;c&quot;}, {4, &quot;d&quot;}, {5, &quot;e&quot;} };
  std::map&lt;int, std::string&gt; results;
  std::copy(entries.begin(), entries.end(),
    map_aggregator(results, concatenateStrings));
  std::copy(entries2.begin(), entries2.end(),
    map_aggregator(results, concatenateStrings));
  // results contains { {1, &quot;a&quot;}, {2, &quot;bb&quot;}, 
  // {3, &quot;cc&quot;}, {4, &quot;dd&quot;}, {5, &quot;e&quot;} }</pre>
  
<p><code>set_aggreagator</code> provides a similar functionality for aggregating elements into sets.</p>

<p>Read the full story about <code>map_aggregator</code> and <code>set_aggregator</code> on my blog [<a href="#[Boccara17b]">Boccara17b</a>].</p>

<h3>override</h3>

<p><code>override</code> is the pipe equivalent to calling <code>begin</code> on an existing collection. The data that <code>override</code> receives overrides the first element of the container, then the next, and so on:</p>

<pre class="programlisting">
  std::vector&lt;int&gt; input = {1, 2, 3, 4, 5, 6, 7, 8,
    9, 10};
  std::vector&lt;int&gt; results = {0, 0, 0, 0, 0, 0, 0,
    0, 0, 0};
  input &gt;&gt;= pipes::filter([](int i)
            { return i % 2 == 0; })
        &gt;&gt;= pipes::override(results);
  // results contains {2, 4, 6, 8, 10, 0, 0, 0, 0, 0};</pre>

<h3>push_back</h3>

<p><code>push_back</code> is a pipe that is equivalent to <code>std::back_inserter</code>. It takes a collection that has a <code>push_back</code> member function, such as a <code>std::vector</code>, and <code>push_back</code>s the values it receives into that collection.</p>

<h3>set_aggregator</h3>

<p>Like <code>map_aggregator</code>, but inserting/aggregating into <code>std::sets</code>. Since <code>std::set</code> values are const, this pipe erases the element and re-inserts the aggregated value into the <code>std::set.</code></p>

<pre class="programlisting">
  struct Value
  {
    int i;
    std::string s;
  };
  bool operator==(Value const&amp; value1, 
    Value const&amp; value2)
  {
    return value1.i == value2.i &amp;&amp; value1.s 
      == value2.s;
  }
  bool operator&lt;(Value const&amp; value1, 
    Value const&amp; value2)
  {
    if (value1.i &lt; value2.i) return true;
    if (value2.i &lt; value1.i) return false;
    return value1.s &lt; value2.s;
  }
  Value concatenateValues(Value const&amp; value1,
    Value const&amp; value2)
  {
    if (value1.i != value2.i) throw
      std::runtime_error(&quot;Incompatible values&quot;);
    return { value1.i, value1.s + value2.s };
  }
  int main()
  {
    std::vector&lt;Value&gt; entries = { Value{1, &quot;a&quot;},
      Value{2, &quot;b&quot;}, Value{3, &quot;c&quot;}, Value{4, &quot;d&quot;} };
    std::vector&lt;Value&gt; entries2 = { Value{2, &quot;b&quot;},
      Value{3, &quot;c&quot;}, Value{4, &quot;d&quot;}, Value{5, &quot;e&quot;} };
    std::set&lt;Value&gt; results;
    std::copy(entries.begin(), entries.end(),
      pipes::set_aggregator(results,
      concatenateValues));
    std::copy(entries2.begin(), entries2.end(),
      pipes::set_aggregator(results,
      concatenateValues));
    // results contain { Value{1, &quot;a&quot;}, Value{2,
    // &quot;bb&quot;}, Value{3, &quot;cc&quot;}, Value{4, &quot;dd&quot;}, 
    // Value{5, &quot;e&quot;} }
  }</pre>

<h3>sorted_inserter</h3>

<p>In the majority of cases where it is used in algorithms, <code>std::inserter</code> forces its user to provide a position. It makes sense for un-sorted containers such as <code>std::vector</code>, but for sorted containers such as <code>std::set</code>, we end up choosing begin or end by default, which doesnâ€™t make sense:</p>

<pre class="programlisting">
  std::vector&lt;int&gt; v = {1, 3, -4, 2, 7, 10, 8};
  std::set&lt;int&gt; results;
  std::copy(begin(v), end(v),
    std::inserter(results, end(results)));</pre>
	
<p><code>sorted_inserter</code> removes this constraint by making the position optional. If no hint is passed, the container is left to determine the correct position to insert:</p>

<pre class="programlisting">
  std::vector&lt;int&gt; v = {1, 3, -4, 2, 7, 10, 8};
  std::set&lt;int&gt; results;
  std::copy(begin(v), end(v),
    sorted_inserter(results));
  //results contains { -4, 1, 2, 3, 7, 8, 10 }</pre>
  
<p>Read the full story about <code>sorted_inserter</code> on my blog [<a href="#[Boccara17c]">Boccara17c</a>].</p>

<h3>to_out_stream</h3>

<p><code>to_out_stream</code> takes an output stream and sends incoming to it:</p>

<pre class="programlisting">
  auto const input =
    std::vector&lt;std::string&gt;{&quot;word1&quot;, &quot;word2&quot;,
    &quot;word3&quot;};
  input &gt;&gt;= pipes::transform(toUpper)
        &gt;&gt;= pipes::to_out_stream(std::cout);
  // sends &quot;WORD1WORD2WORD3&quot; to the standard output</pre>

<h2>References</h2>

<p class="bibliomixed"><a id="[Boccara]"></a>[Boccara] Jonathan Boccara, â€˜Setsâ€™, on <a href="https://github.com/joboccara/sets">https://github.com/joboccara/sets</a></p>

<p class="bibliomixed"><a id="[Boccara17a]"></a>[Boccara17a] Jonathan Boccara, â€˜How to Use the STL With Legacy Output Collectionsâ€™, published 24 November 2017, available at <a href="https://www.fluentcpp.com/2017/11/24/how-to-use-the-stl-in-legacy-code/">https://www.fluentcpp.com/2017/11/24/how-to-use-the-stl-in-legacy-code/</a></p>

<p class="bibliomixed"><a id="[Boccara17b]"></a>[Boccara17b] Jonathan Boccara, â€˜A smart iterator for aggregating new elements with existing ones in a map or a setâ€™, published 21 March 2017, available at <a href="https://www.fluentcpp.com/2017/03/21/smart-iterator-aggregating-new-elements-existing-ones-map-set/">https://www.fluentcpp.com/2017/03/21/smart-iterator-aggregating-new-elements-existing-ones-map-set/</a></p>

<p class="bibliomixed"><a id="[Boccara17c]"></a>[Boccara17c] Jonathan Boccara, â€˜A smart iterator for inserting into a sorted container in C++â€™, published 17 March 2017, available at <a href="https://www.fluentcpp.com/2017/03/17/smart-iterators-for-inserting-into-sorted-container/">https://www.fluentcpp.com/2017/03/17/smart-iterators-for-inserting-into-sorted-container/</a></p>

<p class="EditorInto">This article was first published on Github: <a href="https://github.com/joboccara/pipes">https://github.com/joboccara/pipes</a>.

<p class="bio"><span class="author"><b>Jonathan Boccara</b></span> is a Principal Engineering Lead at Murex where he works on a large C++ codebase. His focus on making code more expressive. He blogs intensively on Fluent C++ and wrote the book <em>The Legacy Code Programmerâ€™s Toolbox</em>.</p>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
