Writing binary data to a file in C is simple: use fwrite, passing the address of the object you want to write and the size of the object. Is there something more "correct" for Modern C++ or should I stick to using FILE* objects? As far as I can tell the IOStream library is for writing formatted data rather than binary data, and the write member asks for a char* leaving me littering my code with casts.
So the game here is to enable argument dependent lookup on reading and writing, and make sure you don't try to read/write things that are not flat data.
It fails to catch data containing pointers, which also should not be read/written this way, but it is better than nothing
namespace serialize {
namespace details {
template<class T>
bool write( std::streambuf& buf, const T& val ) {
static_assert( std::is_standard_layout<T>{}, "data is not standard layout" );
auto bytes = sizeof(T);
return buf.sputn(reinterpret_cast<const char*>(&val), bytes) == bytes;
}
template<class T>
bool read( std::streambuf& buf, T& val ) {
static_assert( std::is_standard_layout<T>{}, "data is not standard layout" );
auto bytes = sizeof(T);
return buf.sgetn(reinterpret_cast<char*>(&val), bytes) == bytes;
}
}
template<class T>
bool read( std::streambuf& buf, T& val ) {
using details::read; // enable ADL
return read(buf, val);
}
template<class T>
bool write( std::streambuf& buf, T const& val ) {
using details::write; // enable ADL
return write(buf, val);
}
}
namespace baz {
// plain old data:
struct foo {int x;};
// not standard layout:
struct bar {
bar():x(3) {}
operator int()const{return x;}
void setx(int s){x=s;}
int y = 1;
private:
int x;
};
// adl based read/write overloads:
bool write( std::streambuf& buf, bar const& b ) {
bool worked = serialize::write( buf, (int)b );
worked = serialize::write( buf, b.y ) && worked;
return worked;
}
bool read( std::streambuf& buf, bar& b ) {
int x;
bool worked = serialize::read( buf, x );
if (worked) b.setx(x);
worked = serialize::read( buf, b.y ) && worked;
return worked;
}
}
I hope you get the idea.
live example.
Possibly you should restrict said writing based off is_pod not standard layout, with the idea that if something special should happen on construction/destruction, maybe you shouldn't be binary blitting the type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With