Elegant output separators Today I found myself reinventing output separators for the zillionth time.

I have converged on an approach like the following that seem pretty clean:

Live On Coliru

#include &lt;iostream&gt;

void foo(int a, int b) {
    auto sep = [first=true]() mutable { return std::exchange(first, false); };

    std::cout &lt;&lt; "foo(";
    if (a) std::cout &lt;&lt; sep() &lt;&lt; "a:" &lt;&lt; a;
    if (b) std::cout &lt;&lt; sep() &lt;&lt; "b:" &lt;&lt; b;
    std::cout &lt;&lt; ")\n";
}

int main() {
    foo(0,0);
    foo(0,1);
    foo(2,3);
    foo(4,0);
}


Extracting Building Blocks?

This could be made a bit more general by extracting the mutating state:

template &lt;typename T = bool, T initial = true, T fallback = false&gt;
struct once {
    mutable T flag = initial;

    operator T() const { return std::exchange(flag, fallback); }
};


So that we can now write the sep() lambda as:

auto sep = [first=once{}]{ return first? "" : ", "; };


Abstracting The Whole One-Off Value

We can go one better using

    auto sep = one_off("", ", ");


With:

template &lt;typename T = char const*&gt;
struct one_off {
    mutable once&lt;&gt; flag;

    T first, other;
    one_off(T first, T other) : first(std::move(first)), other(std::move(other)) {}

    operator T() const { return flag? first : other; }
};


Used as: Live On Coliru

void foo(int a, int b) {
    auto sep = one_off("", ", ");

    std::cout &lt;&lt; "foo(";
    if (a) std::cout &lt;&lt; sep &lt;&lt; "a:" &lt;&lt; a;
    if (b) std::cout &lt;&lt; sep &lt;&lt; "b:" &lt;&lt; b;
    std::cout &lt;&lt; ")\n";
}


Reflection And Merit?

As you can see these are all potentially useful building blocks. I'm wondering whether anyone else uses similar building blocks and what they learned from actual usage.

Ideas:


what about a dynamic separator? It's much easier to capture, say, columnar formatting in a stateful lambda eg: Live On Coliru

void foo(std::vector&lt;int&gt; const&amp; v) {
    auto sep = [n=0u]() mutable {
        if (n++)
            return n%5==1?"\n" : ", ";
        return "";
    };

    for (auto&amp; el : v)
        std::cout &lt;&lt; sep() &lt;&lt; std::setw(5) &lt;&lt; el;
    std::cout &lt;&lt; "\n";
}

Doesn't this conflict with standard library concepts like std::once_flag from C++11 too much?
Intuitively I feel these don't mix too well. Say, we want a every_nth style value wrapper instead of one_off (to replace every nth, instead of just the first)? Suppose we want to return from an input sequence, transforming every nth? Aren't we at risk of reinventing a Range Library?
Conversely, is there a straight-forward way to express these building blocks using an existing (range) library such as Boost Range or RangeV3?



  Notes: 
  
  
  I used C++17 for brevity of exposition; it's not about using C++17 (I'm aware of ostream_joiner).
  It's not about string joining per se, which is why I chose a contrived example. In this example, obviously you could just print the delimiter if (a &amp;&amp; b) but that's not the point of the exercise.
  Thanks to @LucDanton for suggesting std::exchange
That's fine as far as it goes.
Though I am not sure why you want all the added complexity for a problem that seems to be already solved.

What I think we all want is to stream containers in a logical way, that is consistent across containers.

Your basic example:

for(auto const&amp; el: c) {
    std::cout &lt;&lt; sep() &lt;&lt; el;
std::cout &lt;&lt; "\n";


This is a specialization of how I would want containers to be stremed:

auto sep = one_off("", sepObject);
stream &lt;&lt; beginMarker;
for(auto const&amp; el: c) {
    stream &lt;&lt; sep() &lt;&lt; el;
stream &lt;&lt; endMarker;


So for example:

// An array looks like this:
[ 1, 2, 3, 4, 5, 6 ]        // Note terminator is "]\n"

// A map look like this:
{ a =&gt; b, c =&gt; d, e =&gt; f }


So would it be not more logical to define a container streamer object.

std::Container  c = {1,2,3,4,5};
ContainerStream(std::cout) &lt;&lt; c;


Then you can use traits to define the beginMarker, endMarker and sepObject.

Or alternatively rather than wrapping the stream we could potentially wrap the container in something that knows how to print it (and generalize that).

std::cout &lt;&lt; jsonExport(c);