I have a template function for converting an object to a string (this is from a library, I can't change this):
template <typename Q> std::wstring ToString(const Q& q) { static_assert(false, "Must specialise"); }
Now, I want to call it with a parameter of std::vector<Gene>
, where Gene
is a simple class whose details are not important. Of course, to do this, I need to specialise the template, so I do:
template<> std::wstring ToString(const std::vector<Gene>& q){...}
Suppose I have another class, Cell
, and I want to specialise the ToString
function for a std::vector<Cell>
. I would have to make another explicit specialisation, with the same body as the std::vector<Gene>
version.
The logic for converting a std::vector
doesn't depend on the actual content type (an int, a Gene
, a Cell
, another std::vector
, etc), so it would make sense to create a template specialisation that can work with any std::vector
. But I can't figure out an easy way to do this. For now, I currently have a VectorToString
function, and forward the call from ToString(std::vector<Gene>>)
and ToString(std::vector<Cell>)
, but this still requires me to implement a specialisation for each element type.
So, to the actual question: is it possible to create a single specialisation for an arbitrary std::vector
, and how would I do this? And, as a bonus question, could this be generalised to any arbitrary collection which supports std::begin
and std::end
?
I have looked at this this question and tried declaring a specialisation like this:
template<typename E> std::wstring ToString<std::vector<E>>(const std::vector<E>& t){...}
but this fails with C2768: illegal use of explicit template arguments ("The compiler was unable to determine if a function definition was supposed to be an explicit specialization of a function template or if the function definition was supposed to be for a new function."), which makes sense since we've got the same function name and number of template parameters, and a similar signature.
For reference, I am using Visual C++ 2015 RC, and the original template function originates from the native test library.
You almost did it correctly but in case of functions you shouldn't specialize them, you should simply overload them like so:
template <typename Q> std::wstring ToString(const Q& q) {
return L"Original";
}
template<typename E> std::wstring ToString(const std::vector<E>& t) {
return L"overload";
}
See http://ideone.com/G3r0Vt for an running example.
This works because when selecting the overload to call, const std::vector<E>
is considered to be "better" than const Q&
thus the overload is used.
When using those methods in your code you should consider ADL.