Boost logo

Boost :

From: Oleg Abrosimov (beholder_at_[hidden])
Date: 2006-05-02 13:44:12


Alexander Nasonov:
>
> For to_string functionality, you can use Boost.Format.

cool! but useless ;-(
try to replace examples provided in my original message with
boost::format and ask boosters if they want to use it for daily task of
string conversions.

anyway, the main goal of the library proposed is to provide a
_consistent_ interface for string conversion purposes. The solution
where a number of different and non-coherent components are used to
accomplish logically closely related tasks is _very_ misleading.

>
>> 3) functor adapters to use with std algorithms
> I agree, that's a nice feature. May be we could try to add lambda
> support to it? Something like this: lexical_cast<_1>(_2);

too cool too ;-)

>
>> 4) error handling and reporting. (what kind of error occurred?)
>> * optionally report failing without exceptions raising
>> 5) best performance, especially for built-in types and for use in loops
>
> I think that lexical_cast's performance can be improved. Yesterday I
> wrote a first version of integral2str which is several times faster then
> sprintf("%d"). It doesn't add thousands_sep to output but this can be
> easily changed (assuming that there are 3 digits in a group).

The purpose of the library proposed is to be a simple wrapper around
existing C++ library facilities like iostreams. It doesn't invent new IO
facilities, just provides one simple and consistent interface for string
conversion purposes.

If you succeed with your experiments, your code could be incorporated in
string_cvt implementation details to improve performance in special cases.

>
> I also like this idea:
>
> lexical_cast< boost::array<char, 30> >(INT_MIN);
>
> Unlike builtin arrays, boost::array can be copied and therefore, it can
> be returned from a function. We could get rid of dynamic allocations for
> integral and other common types completely.
> It doesn't meet InputStreamable requirements, though.

The string_cvt library is not rigidly bound to std::basic_string<>
template. The library could be extended to work with any other string
and even nonstring type, like boost::array<>. and it is not required to
be InputStreamable, it should provide an appropriate specialization of
cvt_traits<> template:
// it can be overriden for user-defined strings to support them
template <typename TCont>
struct cvt_traits {
     typedef typename TCont::value_type char_type;
     typedef typename TCont::traits_type traits_type;
     typedef typename TCont::allocator_type allocator_type;
     static const char_type* const c_str_from(TCont const& s) {
         return s.c_str();
     }
     static TCont from_c_str(const char_type* const cs) {
         return TCont(cs);
     }
};

actually, it would be helpful to implement at least experimental support
for such an array object to see if the interface of cvt_traits could be
improved to allow specializations for such types perform faster.

>
>> [ ... skiped ... ]
>> It is clear that lexical_cast is not intended to address (1-4) points in
>> the list above,
>> and even (5). For optimizing conversions in loops you'll need to resort
>> to stringstreams again.
>
> I don't think that stringstreams are the fastest.

yes, but given an object of type T with no accessors but only operators
<< and >> provided the only way would be to use iostreams in some form.

>
>> [ ... skiped ... ]
>> There are short examples of intended usage of this library (for those
>> who are too busy to read the full proposal?s text)
>>
>> // simple initialization usage:
>> string s = string_from(1);
>> int i = from_string(?1?);
>>
>> // embedded in expression usage:
>> double d = 2 + (double)from_string(?1?);
>
> lexical_cast can do this.

exactly!

>>
>> To optimize conversions in a loop one can do:
>> string_cvt cvt(std::ios::hex, std::locale(?loc_name?));
>> string s;
>> for(int i; i < 100; ++i) {
>> string t;
>> cvt(i, t);
>> s += (t + ? ?);
>> }
>
> How use of cvt differs from ostringstream?
>
> std::ostringstream cvt;
> for(int i; i < 100; ++i)
> cvt << std::hex << i;
> std::string s = cvt.str();

Really good question! There is one major difference:
string_cvt is a wrapper not only around iostreams, but around low-level
C-library functions as well. That is why for conversions of built-in
types (as in this simple example) iostreams machinery wouldn't be
involved. As a result, code with "string_cvt" would perform faster at no
cost for programmer.

But the real difference is in separation of streaming and conversion
concepts. It is a "good thing" to use streaming syntax for real
streaming purposes and conversion syntax for conversion purposes. It
gives a clue for those who would read your code later.
To conclude, it improves maintainability.

>> double d = 2.0 + from_string(s); // doesn't works
>> double d = 2.0 + (double)from_string(s); // does
>
> Disadvantages:
>
> 1) Reminds programmers of old-style casts.
> 2) Raise eyebrows of experienced programmers (what is a return type
> of from_string?)

see another post in this topic for my view on C-style cast (not
old-style, please).

> 3) Some coding standards prohibit old-style casts. Your example should be
> rewritten to satisfy those standards:
>
> double d = 2.0 + static_cast<double>(from_string(s));

coding standards are important. to satisfy with them one can rewrote
this as:
double d = 2.0 + static_cast<double>(from_string(s));

or as:
double d = from_string(s);
d += 2.0;

>
> It's worse then from_string<double>(s).
>

0) see other post for my opinion about C-style cast in this case
1) subjective
2) violates the symmetry principle of from_string/string_from functions,
that is why is absolutely inappropriate.

Thank you for your time investment in reading my original mail.

Best,
Oleg Abrosimov.


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