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>> 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 ;
      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;
            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.
        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> >
    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, gregod at, cpdaniel at, john at