Easy Bit IO. Very simple interface works up to N == 64 After reading this question Easy bitset I/O. I wanted to see if there was a simpler way of doing it.

This is how I would define a way of outputting std::bitset&lt;N&gt; to the stream and reading it back in. It works perfectly with current containers.

BitIO.h

// Include guards deliberately not included for simplicity.

#include &lt;bitset&gt;
#include &lt;iostream&gt;

template&lt;int S&gt;
class BitIO
{
    public:
    std::bitset&lt;S&gt;&amp;     data;
    BitIO(std::bitset&lt;S&gt;&amp; data)
        : data(data)
    {}

    friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; stream, BitIO const&amp; value)
    {
        // Currently using just an integer.
        //
        // But we could easily take this a step further and use hex.
        // and pad with 0 to get an exact width (that way we don't need a
        // trailing space).
        //
        // Using a fixed width means we may potentially waste space but can
        // be made to waste the least amount of space possible quite easily.
        //
        // Amount of wasted space would be (4 - (S % 4)) % 4

        return stream &lt;&lt; value.data.to_ullong() &lt;&lt; " ";
    }
    friend std::istream&amp; operator&gt;&gt;(std::istream&amp; stream, BitIO&amp; value)
    {
        // As the current output uses a white space separated
        // unsigned long long it is easy to read it back in using the
        // normal `operator&gt;&gt;`
        //
        // Would be just as simple to convert this function to use
        // a fixed width format to mirror the output. 
        unsigned long long tmp;
        if (stream &gt;&gt; tmp)
        {
            value.data  = std::bitset&lt;S&gt;(tmp);
        }
        return stream;
    }
};


main.cpp

#include "BitIO.h"
#include &lt;vector&gt;

int main()
{
    std::vector&lt;std::bitset&lt;16&gt; &gt;    values { std::bitset&lt;16&gt;(1), std::bitset&lt;16&gt;(2), std::bitset&lt;16&gt;(255) };

    std::copy(std::begin(values), std::end(values), std::ostream_iterator&lt;BitIO&lt;16&gt;&gt;(std::cout));


    std::bitset&lt;16&gt;  data { 129 };
    std::cout &lt;&lt; BitIO&lt;16&gt;(data);

}
The code is relatively short and well-written, so I didn't find many nits to pick.  With that said, here's my review:

Include all needed files

Since std::ostream_iterator is declared in &lt;iterator&gt; that should be among the includes in main:

#include &lt;iterator&gt;


Use appropriate type for template parameter

The std::bitset template is defined as taking std::size_t rather than int, so it would make sense to define the BitIO template similarly:

template&lt;std::size_t S&gt;
class BitIO
{
    // ...
};


One can, of course, still abuse the interface by passing negative numbers but at least the user of the code is forewarned that they will be interpreted as std::size_t rather than as signed numbers.

Consider implementing a move constructor

At the moment, this potential usage cannot compile:

std::cout &lt;&lt; BitIO&lt;16&gt;(std::bitset&lt;16&gt;{ 99 });


It's easily fixed by adding this constructor:

BitIO(std::bitset&lt;S&gt;&amp;&amp; data)
    : data(data)
{}


Maintain parallelism with existing practice

I was surprised to see spaces separating the outputs when none had been specified in the output ostream_iterator.  Although having the space is arguably useful, the choice of separator (if any) should be left up to the user of the template instead of being hardcoded in the operator &lt;&lt; function.  I'd omit the trailing space to allow usage like this:

std::copy(std::begin(values), std::end(values), 
        std::ostream_iterator&lt;BitIO&lt;16&gt;&gt;(std::cout,":"));