I have a template function that should execute different code, depends on the type. The simplified function looks like this:
template<typename T>
std::string test(T value)
{
std::string v;
if(std::is_arithmetic<T>())
{
v = std::to_string(value);
}
else
{
v = std::string(value);
}
return v;
}
Usage:
test("Hello");
test(123);
But I get this error:
In instantiation of void test(T) [with T = const char*]:
error: no matching function for call to to_string(const char*)
note: candidate: std::string std::__cxx11::to_string(int) <near match>
to_string(int __val)
and the same for the following:
to_string(unsigned __val)
to_string(long __val)
to_string(unsigned long __val)
Ok, I understand that in case of, for example const char *
the compilation will fail since there is no std::to_string(const char *)
. but how can I do the code works? Just have to note that in my real code I limit to c 11
.
CodePudding user response:
You now get a taste of why if constexpr
was added to the language. If you need to perform some type-dependent operation as part of your larger algorithm, then in pre-C 17 the way to do that is typically via tag-dispatch
namespace detail {
template<typename T>
std::string stringify(T value, std::true_type) {
return std::to_string(value);
}
template<typename T>
std::string stringify(T value, std::false_type) {
return std::string(value);
}
}
template<typename T>
std::string test(T value)
{
std::string v;
v = detail::stringify(value, std::is_arithmetic<T>());
return v;
}
This is dispatching on two conditions, but the technique can be expanded to multiple overloads, depending on how you construct your tag types. A common example in the standard is iterator categories.
CodePudding user response:
You can apply overloading with SFINAE. E.g.
// for arithmetic types
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, std::string>::type test(T value)
{
std::string v;
v = std::to_string(value);
return v;
}
// for non-arithmetic types
template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value, std::string>::type test(T value)
{
std::string v;
v = std::string(value);
return v;
}