Right now I use the following piece of code to dummily convert basic types (int
, long
, char[]
, this kind of stuff) to std::string
for further processing:
template<class T>
constexpr std::string stringify(const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
however I don't like the fact that it depends on std::stringstream
. I tried using std::to_string
(from C++11's repertoire) however it chokes on char[]
variables.
Is there a simple way offering an elegant solution for this problem?
I believe, the most elegant solution is:
Here, if we can construct
std::string
usingT
(we check it with help ofstd::is_constructible<std::string, T>
), then we do it, otherwise we useto_string
.Of course, in C++14 you can replace
typename std::enable_if<...>::type
with much shorterstd::enable_if_t<...>
. An example is in the shorter version of the code, right below.The following is a shorter version, but it's a bit less efficient, because it needs one extra move of
std::string
(but if we do just a copy instead, it's even less efficient):This version uses implicit conversion to
std::string
then possible, and usesto_string
otherwise. Notice the usage ofstd::move
to take advantage of C++11 move semantics.Here is why my solution is better than the currently most voted solution by @cerkiewny:
It have much wider applicability, because, thanks to ADL, it is also defined for any type for which conversion using function
to_string
is defined (not onlystd::
version of it), see the example usage below. Whereas the solution by @cerkiewny only works for the fundamental types and for the types from which std::string is constructible.Of course, in his case it is possible to add extra overloads of
stringify
for other types, but it is a much less solid solution if compared to adding new ADL versions ofto_string
. And chances are height, that ADL-compatibleto_string
is already defined in a third party library for a type we want to use. In this case, with my code you don't need to write any additional code at all to makestringify
work.It is more efficient, because it takes advantage of C++11 perfect forwarding (by using universal references (
T&&
) andstd::forward
).Example usage:
Alternative, but not recommended approach
I also considered just overloading
to_string
:And a shorter version using implicit conversion to
std::string
:But these have serious limitations: we need to remember to write
to_string
instead ofstd::to_string
everywhere where we want to use it; also it is incompatible with the most common ADL usage pattern:And it's most probable, there are other problems connected with this approach.
Since nobody proposed it, consider using boost::lexical_cast.
This integrates seamlessly with anything that implements std::ostream<< operator and can be extended for custom types.
Although the the question is not of a gimme the code kind, since I already have a solution implemented I thought of sharing it:
Usage:
The simplest solution is to overload for the types you want:
since
to_string
isn't a template you can't specialize it, but fortunately this is easier.The code assumes the array is null terminated, but is still safe if it is not.
You may also want to put the
using
line inside the functions that callto_string
if you have strong feelings about whereusing
belongs.This also has the benefit that if you pass it a non-null-terminated string somehow, it does not have UB as the one argument
std::string
constructor does.As far as I know the only way of doing this is by specialising the template by the parameter type with SFINAE.
You need to include the type_traits.
So instead of your code use something like this:
this test works for me:
Important note: the char arrays passed to this function need to be null terminated!
As noted in the comments by yakk you can get rid of the null termination with:
I'd recommend using
enable_if_t
and if you're going to take in any single character variables you specialize those:Here I'm just specializing
char
. If you need to specializewchar
,char16
, orchar32
you'll need to do that as well.Anyway for non-arithmetic types these overloads will default to using
ostringstream
which is good cause if you've overloaded the extraction operator for one of your classes this will handle it.For arithmetic types this will use
to_string
, with the exception ofchar
and anything else you overload, and those can directly create astring
.Edit:
Dyp suggested using whether
to_string
accepts an argument ofT::type
as myenable_if_t
condition.The simplest solution is only available to you if you have access to
is_detected
in#include <experimental/type_traits>
. If you do just define:Then you can set your code up as:
I asked this question to figure out how to use
to_string
as my condition. If you don't have access tois_detected
I'd highly recommend reading through some of the answers cause they are phenomenal: Metaprograming: Failure of Function Definition Defines a Separate Function