$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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.