Iron Savior
Iron Savior

Reputation: 4368

generic form of std::istream::read?

I'd love it if there was some kind of generic version of std::istream::read, so I could do this:

ClassA func( std::istream& is ) {
  ClassA a;
  is.read(a);
  return a;
}

or

ClassA func( std::istream& is ) {
  return is.read<ClassA>();
}

or maybe even:

ClassA::ClassA( std::istream& is ) {
  is.read(data_member);
}

But I always have to supplement my own generic definitions like so:

template< class T >
void load( T& v, std::istream& is ) {
  is.read((char*)&v, sizeof(v));
};

template< class T >
T load( std::istream& is ) {
  T v;
  is.read((char*)&v, sizeof(v));
  return v;
};

In doing this, I have to provide the stream as a parameter when it seems like maybe it should be a method on a stream object.

load(a.data_member, is);
// vs
is.read(a.data_member);

I have a feeling that maybe I'm thinking about this problem incorrectly or that maybe it's stupid to even want this sort of thing. I think it's silly that I have to tell read() about the size of the read when the compiler can infer it generically.

Is there a better way?

Upvotes: 2

Views: 562

Answers (2)

slaphappy
slaphappy

Reputation: 6999

There's nothing wrong with your load function, just remember that it only works with POD types, so you should add:

static_assert(std::is_standard_layout<T>::value, "A must be a POD type.");

Also, remember to turn on exceptions on your streams, or you won't get any error reporting at all - which is probably why streams don't provide such a way of reading into structs in the first place.

Upvotes: 2

Michael Madsen
Michael Madsen

Reputation: 55009

One option would be to simply wrap the stream. Something along these lines (not tested):

class ObjectStream
{
  std::istream& _is;
  public:
  ObjectStream(std::istream& _is) : _is(is) {};
  template <class T>
  ObjectStream& operator>>(T& v) {
    _is.read((char*)&v, sizeof(T));
    return *this;
  }
}

When you open your stream, simply put it inside an ObjectStream and pass that around instead of your istream - now you're able to read an object simply by doing stream >> obj, similar to how istream overloads >>.

Of course, you can also just use a regular instance method if you prefer that.

Upvotes: 1

Related Questions