|
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