Reputation: 5557
Lets say I have the following:
template <class T>
std::string to_string(const T& item)
{
std::ostringstream ss;
ss << item;
return ss.str();
}
Is it possible to create an overload of to_string
that in the case of being given a std::string
would simply forward the argument without any overhead?
Upvotes: 1
Views: 130
Reputation: 17708
Is it possible to create an overload of
to_string
that in the case of being given astd::string
...
Of course.
std::string to_string(const std::string& str) {
return str;
}
... would simply forward the argument without any overhead?
Not sure what you mean by "forward" here, but...
You could provide another overload on cases where a temporary or std::move
d object is provided as an argument to to_string
. Use an r-value reference for that.
std::string to_string(std::string&& str) {
return std::move(str);
}
Note that the std::move
at the return statement is necessary here, as it would result into a copy if it is not used (the compiler treats all named variables as lvalues, and with str
a named variable, there's the need for std::move
).
Now you have two versions overloaded for std::string
the first will effectively return a copy of the provided argument, while the second one takes advantage temporary objects and explicitly std::move
d objects.
std::string str = "Hello World!";
auto str1 = to_string(str); // *effectively* copies str to str1 [1]
auto str2 = to_string("Hi"); // *effectively* moves the temporary created here [1]
auto str3 = to_string(std::move(str)); // *effectively* moves str to str3; [1]
[1] Actually, there still may be several additional moves involved when returning, and copy-elision optimizations may be applied by the compiler on some cases.
UPDATE
Wouldn't
auto str2 = to_string("Hi");
call the template function, as that does not involve an implicit conversion and is therefor the more suitable overload? link
You're right. With that, you could provide another overload accepting a const char*
std::string to_string(const char* str) {
return str;
}
or you could document the behavior and let (more like force) users to do to_string(std::string("bah"))
. I'm pretty sure you'll provide the overload though :-).
Upvotes: 4
Reputation: 366
If I have understood your problem correctly, then you are asking for "Template Specialization".
template <class T>
std::string to_string(const T& item)
{
std::ostringstream ss;
ss << item;
return ss.str();
}
std::string to_string (const string& item)
{
return item;
}
IMPORTANT NOTE:
In the to_string function we have passed "const string&", therefore function call should be like:
string my_string = "ABC";
to_string (my_string);
to call the specialized function.
If you call to_string like:
to_string ("ABC");
then "std::string to_string(const T& item)" general function would be called instead of specialized function.
I hope that this will solve your query.
Upvotes: 0
Reputation: 109089
I'd add a couple of overloads, one that returns a copy of an lvalue std::string
and another that move
s an rvalue std::string
.
std::string to_string(const std::string& item)
{
return item;
}
std::string to_string(std::string&& item)
{
return std::move(item);
}
std::string s("Hello, World!");
std::cout << to_string(s) << std::endl; // calls the lvalue overload
std::cout << to_string(std::string("Hello, World!")) << std::endl; // calls the rvalue overload
std::cout << to_string(20) << std::endl; // calls the function template
You could also let std::to_string
do the job for cases where T
is numeric by tag dispatching to std::to_string
using std::is_arithmetic<T>
.
template <class T>
std::string to_string_impl(const T& item, std::true_type)
{
return std::to_string(item);
}
template <class T>
std::string to_string_impl(const T& item, std::false_type)
{
std::ostringstream ss;
ss << item;
return ss.str();
}
template <class T>
std::string to_string(const T& item)
{
return to_string_impl(item, std::is_arithmetic<T>{});
}
Finally, if you can use boost, your function can be replaced by boost::lexical_cast
.
auto str = boost::lexical_cast<std::string>(whatever);
Upvotes: 6
Reputation: 4293
If you care about performance, stay away from any stringstream
stream and its ilks, they're sadly incredibly slow. You're correct that you could just introduce an overload such as std::string to_string( const std::string& item )
, and it would be a better match and get selected. There's also boost::lexical_cast
, and perhaps something similar in c++11 ( someone else will have to chip in here ). boost::lexical_cast
however is also very slow due to its internals relying on stringstream
. IMO the best way is to introduce your own function, such as you've done with your to_string
, fallback to boost::lexical_cast
and specialize / overload for your own types. We specialize a lot of our types using boost::spirit::qi
, there's performance comparisons out there which rings true with our tests, it's rather easy to use boost::spirit::qi
and its parsers to get way better performance characteristics than stringstream
.
Upvotes: 0