Boost logo

Boost :

Subject: Re: [boost] [lexical_cast] A suggestion
From: Andrew Troschinetz (ast_at_[hidden])
Date: 2009-01-13 23:56:37


Alexander Nasonov <alnsn <at> yandex.ru> writes:

> This looks interesting but boost::optional<T> is already
> InputStreamable:
> #include <boost/optional/optional_io.hpp>

This sounded really cool to me so I attempted a cursory hack to get
this working. The only way I could figure out how to provide an
override for optional<T> that never throws was to change
detail::lexical_cast from a function to a struct to get partial
template specialization. Maybe there is a better way, I'm new at this.
It seems like there must be because I wound up with lots of almost-
duplicated code.

Here's the old familiar detail::lexical_cast, structified:


And here's the optional<T> specialization:


Initially this didn't work however. I traced it to what might be a bug
in optional_io.hpp's insertion operator:

  if ( in.good() )
  {
    int d = in.get();
    if ( d == ' ' ) /* assuming a space in stream, what if there's
not? */
    {
      T x ;
      in >> x;
      v = x ;
    }
    else
      v = optional<T>() ;
  }

  return in;

With the above insertion operator code, this would fail:

    istringstream si ("test");
    optional<string> o;
    si >> o;
    assert (o); /* fails, would work if si were constructed with "
test" instead */

That seems wrong to my thinking, but maybe there's a reason for the if
(d == ' ') test? If the intent was to simply eat up spare white space,
how about this instead:

    if (in)
    {
        T x;
        if (in >> std::ws >> x)
            v = x;
        else
            v = optional<T>();
    }
    return in;

Using that code in optional_io.hpp, and with the above changes, things
work out just fine:

    int invalid_as_uint = -1;
    int valid_as_uint = 5;
    unsigned default_uint = 6;

    // Normal form, throws.
    try
    {
        unsigned i = lexical_cast<unsigned> (invalid_as_uint);
        cout << i << endl;
    }
    catch (const bad_lexical_cast&)
    {
        cout << "bad lexical cast error" << endl;
    }

    // Overload for lexical_cast<optional<T>>, does not throw.
    optional<unsigned> i = lexical_cast<optional<unsigned> >
(invalid_as_uint);
    if (i) cout << *i << endl;
    else cout << "invalid return value" << endl;

    i = lexical_cast<optional<unsigned> > (valid_as_uint);
    if (i) cout << *i << endl;
    else cout << "invalid return value" << endl;

Also, I would love to see a fallback style lexical_cast for the same
reasons Neil already mentioned.

--
Andrew Troschinetz



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk