I’ve created a small utility function for string conversion so that I don’t have to go around creating ostringstream objects all over the place
template<typename T>
inline string ToString(const T& x)
{
std::ostringstream o;
if (!(o << x))
throw BadConversion(string("ToString(") + typeid(x).name() + ")");
return o.str();
}
I want to provide some specialisations of this method for instances where there is no default overloaded << operator for stringstream (i.e. std::pair, std::set, my own classes) and I’ve run into difficulties with the templating. I will illustrate with the std::pair example, if I want to be able to
string str = ToString(make_pair(3, 4));
the only way I can think of to do it is to define the explicit specialisation for int
template<>
inline string ToString(const pair<int,int>& x)
{
std::ostringstream o;
if (!(o << "[" << x.first << "," << x.second << "]"))
throw BadConversion(string("ToString(pair<int,int>)"));
return o.str();
}
is there a way I can define this for the generic case?
template<>
inline string ToString(const pair<T1,T2>& x)
{
std::ostringstream o;
if (!(o << "[" << x.first << "," << x.second << "]"))
throw BadConversion(string("ToString(pair<T1,T2>)"));
return o.str();
}
Don’t specialize the template, but overload it. The compiler will figure out what function template to take by ordering them according to their specialization of their function parameter types (this is called partial ordering).
In general, partial ordering will result in exactly what you expect. In more detail, consider having these two functions
Now, to see whether one is at least as specialized as the other one, we test the following for both function templates:
Example for the above:
X1intoTgives us some type, call itX1. argument deduction ofX1againstpair<T, U>won’t work. So the first is not at least as specialized as the second template.Y1andY2intopair<T, U>yieldspair<Y1, Y2>. Doing argument deduction againstTof the first template works:Twill be deduced aspair<Y1, Y2>. So the second is at least as specialized as the first.The rule is, a function template A is more specialized than the other B, if A is at least as specialized as B, but B is not at least as specialized as A. So, the second wins in our example: It’s more specialized, and it will be chosen if we could in principle call both template functions.
I’m afraid, that overview was in a hurry, i only did it for type parameters and skipped some details. Look into
14.5.5.2in the C++ Standard Spec to see the gory details. g