
From: "Matt Chambers" <matt.chambers42@gmail.com> ... I agree that in some cases there is no sensible default/fallback value. In those cases, the only concern is whether the conversion succeeded, right? So optional<T> will work fine for that case, but it would have to be renamed so it doesn't conflict with the simple, throwing convert_cast<T>(s): optional<hamlet_problem> t = optional_convert_to<hamlet_problem>(s); This can be in addition to try_convert_to, which would still be useful when both the conversion success and the final value (fallback or not) are wanted.
Again, my typical concern is twofold -- result of conversion and the return value (converted or fallback). The following is my typical use-case (note the second -- to_be -- parameter that you seemingly missed in your example) optional<hamlet_problem> t = optional_convert_to<hamlet_problem>(s, to_be); if (!t) { message("Invalid input. Using fallback"); t = to_be; } Given I might have a dozen of configuration parameters read, I would very much like have it all done with as few lines as possible: pair<hamlet_problem, bool> res1 = optional_convert_to<hamlet_problem>(s, to_be); pair<my_problem, bool> res2 = optional_convert_to<hamlet_problem>(s, why_bother); if (!res1.second) message("Invalid input ... Using fallback"); if (!res2.second) message("Invalid input ... Using fallback"); ... proceed with res1.first which is to_be; ... proceed with res2.first which is why_bother;
In an earlier message you wrote this about the try_convert_to method:
#5 IMO can. It deploys the Pascal-style parameter passing and modifications. I remember reading Stroustrup (I think) long time ago advising against passing non-const references and I personally agree. That's due to potential confusion and wrong expectations. I am not aware of any function in std and boost doing that. Introducing such a precedent might be a hard-sell. If you want a precedent for taking output as a by-reference parameter: boost::algorithm::split.
Great. :-)
Further, I'm not sure how output references could be considered more confusing than the output iterators that are ubiquitous in std algorithms.
Stroustrup. "The C++" #7.2 "... functions that modify call-by-reference arguments can make programs hard to read and should most often be avoided (but see 21.2.1)". I agree whole-heartedly. The output iterators that you mention fall in to the exception category covered in 21.2.1. Our fallback reference not (IMHO). I find the below quite confusing int fallback = 1; int v1 = convert_to("123", fallback); bool converted = try_convert_to<int>("123", fallback); as convert_to does not and try_convert_to does modify 'fallback'. Again, that's my preference and, in fact, I believe it's quite a common view (just see how often modifiable call-by-reference arguments are used).
Outside the enum case, have you considered that your use of convert on so many object types mixes lexical conversion and serialization (admittedly related concepts)?
Well, we indeed use lexical conversion to implement serialization, i.e. conversion to/from textual form. Is it wrong? Indeed, I was pushing that objectified enum case as an example. Primarily due to its simplicity. However, where is that edge where a class which starts as an objectified enumerator acquires enough functionality not to be considered just an objectified enumerator anymore?
In my experience, the former uses a simple, concise interface intended for value types while the latter uses a verbose interface supporting both object types and value types. What's the rationale for a lexical conversion library to support serialization?
To begin with we use lexical conversion to read from config. files. Spot on deployment of lexical conversion, right? I am not sure what you describe as a "simple, concise interface" but we find the interface of lexical_cast to be just way to clunky and insufficient. For us 'convert' is just right. Once one has a decent lexical conversion library I am not sure why he needs to restrict its use to certain cases. After all, a lexical conversion library takes care of "string-ification" of a class. When an object is "stringified", I can easily write it to a file, send it over the network, etc. Then, that object (or rather its copy) is reconstructed from that respective string. That mentioned lexical conversion library takes care of that as well and seemingly does it well. I cannot see anything specifically wrong in deploying a lexical conversion library for the task. Note: I am glad you mentioned "lexical" and "conversion" together as that's exactly how I see lexical_cast which pretends to be a cast when it is not (and I do not like pretenders). It's a converter -- it returns a completely new instance of a different type when a cast returns the same instance but retyped (I am aware that upcast returns a different pointer instance for multiple inheritance). So, I am not thrilled by the latest attempts to continue that pretending business with convert_cast name (not to mention it is an oxymoron -- convert and cast are quite different operations). Why can't things be called as they are -- 'convert' if we are converting, 'cast' is (and when) we are casting. Those are merely my views. I am not fighting anyone or anything. I am not forcing anyone to share those views and not pushing for any particular interface based on those views. Please proceed as you feel appropriate in whatever direction you want to proceed. Best, V.