Boost logo

Boost :

Subject: Re: [boost] Formal Review Request: Boost.String.Convert
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2009-02-18 17:05:48


Emil Dotchevski wrote:

> You can still do this with what I am proposing. When someone does
>
> foo x;
> std::string s=to_string(x);
>
> this would bind to the foo to_string overload if available, if not it
> would bind to the foo/ostream overload of << if available, etc. The
> idea is to automatically pick the best conversion available to produce
> the string the caller needs.
>
> This makes the to_string library implementation more complex, but the
> benefit is that it is possible to define simple, non-template
> to_string overloads for various types. The reason I like that is
> because I don't have to put to_string implementations in headers.
>
> Also, it makes it very easy to integrate 3rd party types into the
> framework. Suppose you have something like:
>
> class bar
> {
> public:
> std::string getstr() const;
> private:
> ...
> };
>
> and you want to integrate it into the to_string framework. All you
> have to do is (presumably you can't alter bar itself):
>
> std::string to_string( bar const & x ) { return x.getstr(); }
>
> (note, no coupling between the above to_string overload and the
> to_string library) and now you can do:
>
> bar x;
> std::wstring s=to_wstring(x); //the library handles string->wstring
> conversion automatically.

And what if I write my own class outer_bar that owns bar and also want
to be ostreamable? I would have to duplicate my operator<< in order to
call either to_string or to_wstring, wouldn't I?

   struct outer_bar
   {
     bar b_;

     friend std::ostream& operator<< (
       std::ostream& s, outer_bar const& ob)
     {
        return s << to_string(ob.b_);
     }

     friend std::wostream& operator<< (
       std::wostream& s, outer_bar const& ob)
     {
        return s << to_wstring(ob.b_);
     }
   };

Things will get even worse with char16_t and char32_t.

Why not make it a template? It would still cover your case just fine:

   struct outer_bar
   {
     bar b_;

     template< typename CharT, typename TraitsT >
     friend std::basic_ostream< CharT, TraitsT >&
       operator<< (
         std::basic_ostream< CharT, TraitsT >& strm,
         outer_bar const& ob)
     {
       typedef std::basic_string< CharT, TraitsT > string_t;
       return s << convert< string_t >(ob.b_);
     }
   };

And supporting bar for the templated "convert" is no less difficult than
what you suggested:

   template< typename StringT >
   StringT convert(bar const & x);

   template< >
   std::string convert(bar const & x) { return x.getstr(); }

   template< >
   std::wstring convert(bar const & x)
   {
     return convert< std::wstring >(convert< std::string >(x));
   }

The equivalent of the latter specialization will be needed in your
approach, too. If the library is clever enough, it may be done in
generic manner in the library itself.


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