通用形式的std :: istream :: read?

时间:2013-06-04 15:39:20

标签: c++ generics c++11 iostream

如果有某种std::istream::read的通用版本,我会喜欢它,所以我可以这样做:

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

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

或者甚至可能:

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

但我总是要补充我自己的通用定义,如下所示:

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;
};

在执行此操作时,我必须提供流作为参数,因为它似乎应该是流对象上的方法。

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

我有一种感觉,也许我错误地想到了这个问题,或者甚至想要这样的事情也许是愚蠢的。我认为当编译器可以推断它时,我必须告诉read()关于读取的大小是愚蠢的。

有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

您的load功能没有任何问题,请记住它只适用于POD类型,因此您应该添加:

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

另外,请记住打开流上的异常,否则根本不会收到任何错误报告 - 这可能就是为什么流不提供这种首先读取结构的方式。

答案 1 :(得分:1)

一种选择是简单地包装流。沿着这些方向的东西(未经测试):

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;
  }
}

当你打开你的流时,只需将它放在ObjectStream内并传递它而不是你的istream - 现在你只需要通过stream >> obj来读取一个对象,类似于istream重载>>

当然,如果您愿意,也可以使用常规实例方法。