On 2014-02-03 19:26, Thiago Macieira wrote: > Em seg 03 fev 2014, às 15:29:06, Matthew Woehlke escreveu: >> If I were designing such an API from scratch, I'd probably these days go >> with something like the std::expected approach. Bonus points for >> implicitly converting to the value type. >> >> Then you could write e.g.: >> >> auto const result = s.toInt(); // Other params (e.g. base) elided >> if (result.isOkay()) >> use(result.value()); // '.value()' optional >> >> - or - >> >> // Can use value directly, as before >> use(s.toInt()); >> >> - or - >> >> // Use default value on error >> use(s.toInt().value(default)); > > Sounds good, but should I then create a QExpected class? And how should I make > it differ from QOptional?
I'm leaning more now toward having a separate (template) class for numeric conversions. I would strongly look into having that class *subclass* (or at least have as a member) QOptional, however. (But also see rest of my reply, especially the last two paragraphs.) You talked about returning information about how many characters were processed; presumably the return class would contain that information as well as the value. It may also contain extended error information (the ISO proposed version definitely would, but I could see Qt omitting that... up to you). > Since we won't have exceptions in our QOptional, I don't think we need two > classes. One would suffice. And then we can add it to our containers too, but > probably only for Qt 6 due to BIC issues (QVector on MSVC). Yeah, I'm not entirely on board with the whole "check the result or your program dies" idea. Qt doesn't do that now; I definitely don't feel like it needs to be added. (I guess QOptional will still assert though if you call value() and it is disengaged? Just like a container would when using operator[] on a non-existing index?) >> - Should toInt() also take a default value? > > Either it takes a default value or it returns a QOptional. Not both. Agreed. Probably I would go with the QOptional (subclass), and use whatever is QOptional's equivalent of value_or() to implement default values. >> - operator bool could be ambiguous for toBool (though I think Qt doesn't >> have this (currently)?), so I went with an explicit isOkay() to test the >> result. Should there be an operator bool -> isOkay() for toX, x != Bool? > > We don't have toBool(). We'd probably name isOkay() instead isValid(). We > should probably also adopt std::optional names and add an isEngaged(). Yes, for QOptional you wouldn't want to name it 'isOkay()'. But you *will* have the problem of ambiguous implicit conversion with QOptional<bool>, which I assume will be allowed even if there is no QString::toBool(). Alternatively you could omit implicit value conversion entirely and require to use either value() or operator*() (hmm, now I wonder if the std::optional proposal had an operator*()... it is almost as good as an implicit conversion to the value type, but without ambiguity problems, and slightly more explicit while still being much less typing than ".value()".) Other names WFM. >> Do we need that for e.g. 'if (auto const result = s.toInt())'? >> Alternatively, the implicit conversion could be omitted and require the >> user to use .value(). > > In the above, result is a QOptional<int>. The question is what use you make of > it. The point was, the above expression only makes sense if there is an operator bool() -> isValid(). I hadn't thought of it before; now that I have, I'm strongly leaning toward operator bool() -> isValid() and operator*() -> value(). >> As an added benefit, isOkay() could take parameters or have alternate, >> similar methods (isComplete()?) to clarify what "okay" means (e.g. did >> it consume the entire input?). However it may be better to specify that >> as an input parameter. (Unrelated: it's sure nice in this context to >> have a flags class :-)...) > > That makes it too complex for QOptional or QExpected. Instead, toIntegral() > should have extra parameters. Yes, we agree :-). > The task I have is to add the endposition output parameter. If that pointer is > non-null, it will indicate the position (index) of where the conversion ended, > so you can resume the parsing. If it is null, we fall back to the current > behaviour: fail if endposition != length(). That could work... Pros: - makes implicit whether to allow trailing text - return can be QOptional Cons: - it's an output parameter I would at least consider, if you haven't, taking a QFlags parsing options for e.g. if trailing text is allowed, if whitespace should be ignored, and anything else that makes sense. The "endpos" could be a member of the return type. > That means the front-end function would be: > > template <typename T> QOptional<T> toIntegral(int base = 10, int *endpos = > 0) > // plus the enableif integral type Consider 'toNumber' so that it can take either integral or floating point types? -- Matthew _______________________________________________ Development mailing list [email protected] http://lists.qt-project.org/mailman/listinfo/development
