Boost logo

Boost :

Subject: Re: [boost] Formal Review Request: Boost.Convert
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2009-02-24 13:43:59


Sorry for the late reply, it's been a busy weekend. I'm glad to see that
others answered some of your questions.

Vladimir Batov wrote:

>> You can add new keywords as needed.
>
> Where can I add those "new keywords" to? If it is into convert(), then
> I do not feel it is appropriate as for every user "needed" will be
> different and I cannot see convert() collecting *all* those "needed"
> keywords from every user on the globe.
>
>> The point is that the underlying conversion mechanism can support a
>> subset of these keywords, specific to the conversion domain. This way
>> it will be a non-intrusive extension.
>
> I cannot understand how it can be a "non-intrusive extension" if every
> new keyword needs to be stored/registered *inside* convert<string,
> int>... unless I misunderstand something. With manipulators (however
> clumsy they are) convert<string, int> knows nothing about std::hex.
> Still, when std::hex is plugged in, we get 0xFF. How do you do that with
> "radix_"? The keyword has to be registeded with convert<string, int> and
> then convert<> needs to apply that somehow.

My initial post wasn't specifically about string-related conversions,
however, the main plot is still applicable.

Assume we want to make a numeric conversion, but we also want to detect
truncation and treat it as an error:

   int i = 0xFFFFFFFF;
   short j = convert< short >(i, throw_on_overflow_ = true);

Now, that kind of conversion could be handled by
Boost.NumericConversion, something like this (pseudocode):

   BOOST_PARAMETER_KEYWORD(throw_on_overflow_)

   template< typename ToT, typename ArgsT >
   ToT convert_impl(ArgsT const& args)
   {
     bool throw_on_overflow = args[throw_on_overflow_ | false];
     return numeric_cast< ToT >(args[source_], throw_on_overflow);
   }

You can see that the convert_impl accepts a single arguments pack that
accommodates all named arguments passed to the "convert" function,
including the source value i, which has the implicit name "source_". You
can also see that the "throw_on_overflow_" keyword belongs to the
Boost.NumericConversion library, and Boost.Convert does not need to know
anything about it.

As for the "string<->numeric" conversions, the approach is the same with
one exception: such conversions can be made by Boost.Convert itself.
This means that Boost.Convert may introduce its own keywords to
customize the conversion (such as radix_, bool_alpha_, etc.)

One dark corner that needs to be settled in this scheme is to figure out
how Boost.Convert will decide which convert_impl should be called. This
needs to be thought about, however, I think, using a number of traits on
the source and target types, yielding some tag type to dispatch between
convert_impl functions would suffice.

> Secondly, I do not feel there is much conceptual difference between
>
> convert<string, int>(str, radix_ = 16)
> and
> convert<string, int>(str).radix(16) // 16 passed in differently
> or
> convert<string, int>(str) >> radix(16) // different op>>
> or
> convert<string, int>(str) >> std::hex
>
> The difference is that in #1 convert() has to handle "radix_" itself and
> in #4 convert() knows nothing about std::hex. Am I missing something?

Like I said, using manipulators is sufficient for string-related
conversions, but is pretty meaningless for other types of conversion.
You could implement your own manipulator-like modifiers even for other
conversions, but it would look unnatural and more complex than using
keywords. For example, here's how wstring->string conversion could look
like:

   string s = convert< string >(ws) >> replace_non_convertible_with('?');

or:

   string s = convert< string >(ws, replace_non_convertible_with_ = '?');

Personally, the latter looks more appealing to me.

> RE: algorithms
>
> I've extended convert to be used with algorithms as
>
> std::vector<string> strings;
> std::vector<int> integers;
> ...
> std::transform(
> strings.begin(),
> strings.end(),
> std::back_inserter(integers),
> convert<string, int>(string(), -1));
>
> No formatting. I feel it is the best I can do (well, so far).

Do you intentionally use the "convert" verb for the functor name?
Traditionally, functors and other classes use nouns in their names, like
"converter".


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk