Reputation: 217
If I have here DATA_T = std::string, I can't compile this code, because of error "no matching function for call to 'to_string'". The function does not allow converting a string to a string. But I need to get the string anyway, how can I work around this error and compile the program?
template <typename DATA_T>
std::string get_string(DATA_T subdata) {
std::string data = "...";
if (typeid(subdata) == typeid(std::string))
data += subdata;
else
data += std::to_string(subdata);
return data;
}
Upvotes: 4
Views: 1751
Reputation: 122133
As shown in other answers you can add a special case for std::string
. This will solve your problem with std::string
, but how about other types?
When I first saw to_string
I was rather disappointed, because it has only a finite set of overloads. However, I misunderstood what to_string
is meant for. It is meant to convert to string exactly as std::sprintf
would do with the right format specifier. As sprintf
is inherited from C, it cannot convert all types to string that you can convert to string in C++. There is no way to enable conversion of custom types via sprintf
directly. And because of that, to_string
has the same limitations. In particular there is no to_string(const std::string&)
.
Overloading std::ostream& operator<<(std::ostream&,const T&)
is more flexible. You want to call get_string
with a foo
or a bar
? Why not:
#include <iostream>
#include <sstream>
template <typename DATA_T>
std::string get_string(DATA_T subdata) {
std::stringstream data;
data << "...";
data << subdata;
return data.str();
}
struct foo {};
std::ostream& operator<<(std::ostream& out,const foo& f){
return out << "foo";
}
int main() {
foo f;
std::cout << get_string(f);
}
If you actually do want to convert like sprintf
does, I'd probably stay with one of the solutions presented in the other answers.
Upvotes: 4
Reputation: 5565
Instead of trying to branch on the type of a template argument inside the body of your function, you can write an overload that will be preferred when the argument is a std::string
.
template <typename DATA_T>
std::string get_string(DATA_T subdata) {
std::string data = "...";
data += std::to_string(subdata);
return data;
}
std::string get_string(std::string subdata)
{
std::string data = "...";
data += subdata;
return data;
}
Upvotes: 11
Reputation: 22176
With C++17 it can be made simpler using if constexpr
:
#include <string>
#include <type_traits>
template <typename DATA_T>
std::string get_string(DATA_T subdata) {
std::string data = "...";
if constexpr (std::is_same_v<DATA_T, std::string>)
data += subdata;
else
data += std::to_string(subdata);
return data;
}
See the other answer for a pre-C++17 solution.
Upvotes: 11