3

Since the names of to_string() and to_wstring() differ, it's practically impossible to use them in generic functions. So, I'm planning to unite them with the following:

template <typename CharT, typename T>
auto to_xstring(const T& x);

The question is how to implement such a function template succinctly.

My current implementation is somewhat clumsy (with a detail namespace even). Since C++ does not allow partial specialization of function templates, I have the function template dispatch to structs that can be partial specialized. I'm looking for a better implementation.

namespace detail {

template <typename>
struct to_xstring_helper;

template <>
struct to_xstring_helper<char> {
  template <typename T>
  static std::string invoke(const T& x) {
    // explicitly pulls in `std` in case `T` is not a class type
    using std::to_string;
    return to_string(x);
  }
};

template <>
struct to_xstring_helper<wchar_t> {
  template <typename T>
  static std::wstring invoke(const T& x) {
    // explicitly pulls in `std` in case `T` is not a class type
    using std::to_wstring;
    return to_wstring(x);
  }
};

} // namespace detail

/// Calls either `to_string(x)` or `to_wstring(x)` based on `CharT`. Lookups in
/// namespace `std` and that of `T` (by ADL). Given a uniform name, this
/// function template facilitates writing generic functions.
template <typename CharT, typename T>
auto to_xstring(const T& x) {
  return detail::to_xstring_helper<CharT>::invoke(x);
}
Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • The fact that "you can't have return type only difference in a function" is the reason that there is a `to_string` and `to_wstring` in the first place, so you can't avoid using some kind of struct/class as a helper. – Mats Petersson Jan 23 '16 at 08:53
  • @BarmakShemirani: Because `to_string` and `to_wstring` are declared as `template std::string& to_string` and `template std::wstring& to_wstring`, so you still need some way to produce one function that returns a different type based on the return value. But it may work a little better to do `std::basic_string tmp; my_to_xstring(tmp, x); return tmp;` [this relies on knowing how `std::wstring` or `std::string` are declared via `std::basic_string`, but I think that is part of the standard. – Mats Petersson Jan 23 '16 at 08:58
  • @MatsPetersson I don't think so. The functions differ not only in the return type but also in the template argument `CharT`. – Lingxi Jan 23 '16 at 08:58
  • Right, I meant for the actual `to_xstring` implementation itself - you need a function that can be ditinguished by the compiler, and you can't have two functions that are ONLY different in terms of return value. – Mats Petersson Jan 23 '16 at 09:02
  • @MatsPetersson I just realized that parameter overloading doesn't apply. I deleted my comment before you posted the reply. – Barmak Shemirani Jan 23 '16 at 09:03

2 Answers2

4

You could use SFINAE for this, no? E.g., using std::enable_if:

template <typename CharT, typename T>                                                                                                                                                                    
typename std::enable_if<std::is_same<CharT, char>::value, std::string>::type 
    to_xstring(const T &t)
{
    return std::to_string(t);
}


template <typename CharT, typename T>
typename std::enable_if<!std::is_same<CharT, char>::value, std::wstring>::type 
    to_xstring(const T &t)
{
    return std::to_wstring(t);
}
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
2

You can use static dispatch without a template struct and partial specialization, for instance like this:

namespace detail {

  template<typename T>
  std::string to_string_helper_impl(const T& x, char) {
    using std::to_string;
    return to_string(x);
  }

  template <typename T>
  static std::wstring to_string_helper_impl(const T& x, wchar_t) {
    using std::to_wstring;
    return to_wstring(x);
  }

}

template <typename CharT, typename T>
auto to_xstring(const T& x) {
  return detail::to_string_helper_impl(x, CharT{});
}
Rumburak
  • 3,416
  • 16
  • 27