
On 5/4/2011 8:01 AM, Gordon Woodhull wrote:
So, here's something complete (?) for people to rip apart:
int i = convert_cast<int>(s); // default behavior: might throw optional<int> i = convert_cast<int>(s, use_optional_instead_of_throwing_); int i = convert_cast<int>(s, 17); // won't throw; can't tell if conversion successful int i = convert_cast<int>(s, 17, throw_even_though_i_specified_a_failback_); optional<int> i = convert_cast<int>(s, 17, use_optional_instead_of_throwing_); pair<bool,int> i = convert_cast<int>(s, 17, fallback_and_report_success_);
I am not concerned with names, just with syntax. So I'm using "convert_cast" although I actually don't care what it's called, and I have some very ugly very descriptive tag values with distinct types to trigger different overloads, which might be abbreviated dont_throw_, do_throw_, and, um, tell_fallback_ or something.
All would also accept extra manip_/format_= and locale_ arguments as in Vladimir's proposal, except they have to be appended to the first parameter list because of the "no proxies" requirement.
Doesn't this now cover all the functionality we've been talking about?
The 5th and 6th forms cover nondefaultable types / types with no sentinel value, and Vladimir's "print a warning if failing back" use-case.
You mention noncopyable types but I'm not able to find any reference to that in the documentation or in previous discussion. I don't see how the value can be non-copyable since it's being returned by the function.
I'd actually prefer the behavior flags were put in the template parameters, because they affect the return type, but that would be tricky because of the defaulted Destination type. (I don't think it's impossible, but it might be messy.)
Maybe just having more functions would be simpler; I'm just taking an idea to its conclusion.
I definitely could do without the tags to pick an overload. I'd much rather have the try_ prefix. So: int i = convert_cast<int>(s); // default behavior: might throw int i = convert_cast<int>(s, 17); // won't throw; can't tell if conversion successful; but how often do people actually care about that if they're providing a fallback value? it's still very practical and useful! optional<int> i = try_convert_cast<int>(s); // won't throw; specialized version of optional is not necessary since there's no fallback value convert<int>::result i = try_convert_cast<int>(s, 17); // won't throw; specialized version of optional is necessary to detect failure // I'd get rid of these: //int i = convert_cast<int>(s, 17, throw_even_though_i_specified_a_failback_); // what's the purpose of this overload? //optional<int> i = try_convert_cast<int>(s, 17); // this doesn't allow checking for failure, so there's not much point //pair<bool,int> i = convert_cast<int>(s, 17, fallback_and_report_success_); // it's burning my eyes
Finding the right prefix for "_cast" will be a challenge. Sigh, another naming debate. (Naming is important but so difficult!) It does seem like the direction that *_cast<>() is clearer to people than convert<>()
I also like as<>() :-) but somehow I don't think that'll generate consensus. The first overload is a drop-in replacement for lexical_cast as far as I'm concerned (even with additional arguments for locale and manipulators). If it can pass all the lexical_cast tests, what's the harm?
-Matt