Question

template <class T>
T Read () {
  T t;
  cin >> t;
  if (cin.fail()) {
    // ...
  }
  return t;
}

This generic code read value of type T with some additional error handling. It relies on having operator>> that can parse T, and in this way it is extensible to new types.

What I didn't realize is that it relies on T having a default constructor. Now I've hit into this problem.

What are my options?

What is the right way to do it?

Was it helpful?

Solution

Streaming from an input stream always assumes a fully constructed object to write into. You can't get around having to construct an object, all you can do is allow for different ways to do so.

One way to do this could be traits. The standard traits would do what you're doing:

template< typename T >
struct istream_traits
{
  inline static T read(std::istream& is)
  {
    T obj;
    is >> obj;
  }
}

template< typename T >
inline T read(std::istream& is)
{
  is >> std::ws;
  T obj = istream_traits<T>::read(is);
  is >> std::ws;
  if(!is.eof()) throw "dammit!";
  return obj; 
}

If you have a type X that cannot be default-constructed, but can be constructed from an istream, the following specialization would do:

template<>
struct istream_traits<X>
{
  inline static X read(std::istream& is)
  {
    return X(is);
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top