views:

71

answers:

2
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?

A: 

Why construct a temporary T and then return a copy of it?

template <class T>
T& Read(T &t) {
    cin >> t;
    if (cin.fail()) {
        // ...
    }
    return t;
}
jamessan
There is a `void` missing...
Georg Fritzsche
Thanks for noticing that, gf. Updated to return the T reference instead, as that's likely more useful.
jamessan
How does that help in solving the 'no default constructor' problem ?
Matthieu M.
+3  A: 

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);
  }
}
sbi
"is >> obj;" is done twice in read and after read.
Łukasz Lew
I guess "istream_traits<T>::read(is);" shoud be "istream_policy<T>::read(is);"
Łukasz Lew
Can I do a massive specialization, ie not for every type separately, but something like "if there is no default constructor try X(istream?
Łukasz Lew
Using Concept Checking + SFINAE, I suppose it would be possible.
Matthieu M.
@Łukasz: I apologize for the silly errors. (It was past 2am, in case this counts as an excuse.) As Matthieu already pointed out, there are template techniques to do such things. As another idea, boost (http://www.boost.org) has a comprehensive type traits library which might have something like `is_default_constructible`. (I haven't used it, so I don't know.) Regarding specializing for "everything else": you do it the other way around and specialize for everything except the "everything else". Read this classic article by Andrei Alexandrescu: http://erdani.com/publications/traits.html.
sbi
@sbi, Thanks. Can I use boost to check it a type has static named constructor OfStream?
Łukasz Lew
@Łukasz: I would suppose, although, as I said, I haven't used this myself yet.
sbi