
2. lexical_cast ignores trailing whitespaces, but not leading whitespaces. Meaning that
int a = lexical_cast<int>("3 "); // three-space
will work and return 3, but
int a = lexical_cast<int>(" 3"); // space-three
will throw. Why? There's no rationale here. Both cases should be treated in the same manner, and IMHO, that manner should be throwing.
So what should lexical_cast do; strip or not? Ladies and gentlemen, can we have your votes? ;)
I am of the opinion we should follow the standard (ie. STL) in this one. The STL would accept both, and since we rely on operator>>, so should we. I mean, if you're going to be anal about spaces, be completely anal about them, but I don't think we should be, I think accepting whitespace before and after is correct, just as the stringstream operator>> does by default.
But lexical_cast is not operator>>, it just uses it. BTW, I've thought of the following (rare) scenario: There's a class A which have operator<< that streams a single space, then its content and then another space at the end. Class A's operator>> requires these leading and traling spaces, otherwise it falis. In this case, a "whitespace-loose" lexical_cast should *know* to bypass all leading spaces in the input string, *except* the last space before the content, and go on to the class A's operator>>. Can he do that? Is this even possible? What I'm saying is that using a "whitespace-loose" lexical_cast, forces us to write "whitespace-loose" operator>>, which I'm not sure is always possible.
Adding options to lexical_cast is difficult. It's meant to resemble regular casts, and any additional template- or function-arguments makes it no longer look like a cast.
Not really, make it a policy - defaulting to one or the other, eg:
myclass a = boost::lexical_cast<myclass>(s); will not care about spaces. myclass a = boost::lexical_cast<myclass, noskipws>(s); will care.
Its easy enough to default the argument: enum ws_policy { skipws, noskipws }; template<typename T, ws_policy wsp = skipws> class lexical_cast { ... };
Or even better: template<typename T, std::ios_base::fmtflags newflags = std::ios_base::skipws> class lexical_cast { ... };
Then just do: std::stringstream ss; ss.flags(newflags);
And carry on about our merry way. The latter way gives us great flexibility - allowing us to control the IOS flags ourselves, while still keeping a simple and backward compatible interface, and most importantly, its dead easy to implement :)
Unfortunately, it's not that easy. calling lexical_cast<T, noskipws> according to your second proposal, will make it not ignore leading whitespace, but it will still ignore trailing whitespace. Ignoring/not ignoring trailing whitespace requires some additional code other than setting ios_base flags. I'm not saying it's not possible, just that it's not that easy :-(