I'm writing an extensible library where it has become convenient to overload STL's to_string()
for custom types. For that I've designed a generic overload template that throws an exception if not specialized:
namespace std {
// ...
template < typename T >
inline std::string to_string(const T& in, const std::string& separator = ",") {
throw std::runtime_error("invalid call to " + std::string(__func__) + "(): missing template specialization for type " + typeid(T).name());
}
} // namespace std
This is useful mainly because the description will provide a clear explanation on the issue and how to solve it, and avoids having to use polymorphism to implement derived implementations (the function is only marginally/optionally required for certain applications such as serialization, I/O, etc.).
However, the issue with this approach is that the overload template will be deduced even with types where <string>
already provides an overload for.
My question is if is there a way to force the non-template overload to be used only when there is no non-template definition available?
I recommend that you do not generate a runtime exception for something that should be a compilation failure.
It could look like this:
#include <string>
#include <type_traits>
namespace extra {
template <class T>
inline std::string to_string(const T& in) {
static_assert(std::is_arithmetic_v<T>, "T needs extra::to_string overload");
return std::to_string(in);
}
} // namespace extra
... and then you don't need to check if it's an arithmetic type at the call site:
template <class T>
void func(const T& arg) {
std::cout << extra::to_string(arg);
}