# 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<N> to the stream and reading it back in. It works perfectly with current containers.

### BitIO.h

// Include guards deliberately not included for simplicity.

#include <bitset>
#include <iostream>

template<int S>
class BitIO
{
public:
std::bitset<S>&     data;
BitIO(std::bitset<S>& data)
: data(data)
{}

friend std::ostream& operator<<(std::ostream& stream, BitIO const& 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 << value.data.to_ullong() << " ";
}
friend std::istream& operator>>(std::istream& stream, BitIO& 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>>
//
// 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 >> tmp)
{
value.data  = std::bitset<S>(tmp);
}
return stream;
}
};


### main.cpp

#include "BitIO.h"
#include <vector>

int main()
{
std::vector<std::bitset<16> >    values { std::bitset<16>(1), std::bitset<16>(2), std::bitset<16>(255) };

std::copy(std::begin(values), std::end(values), std::ostream_iterator<BitIO<16>>(std::cout));

std::bitset<16>  data { 129 };
std::cout << BitIO<16>(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 <iterator> that should be among the includes in main:

#include <iterator>


## 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<std::size_t S>
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 << BitIO<16>(std::bitset<16>{ 99 });


It's easily fixed by adding this constructor:

BitIO(std::bitset<S>&& 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 << function. I'd omit the trailing space to allow usage like this:

std::copy(std::begin(values), std::end(values),
std::ostream_iterator<BitIO<16>>(std::cout,":"));

• The constructor could take its value by const reference and still work (have not tried). But that would make the move constructor redundant. – Martin York Dec 19 '14 at 20:20