Reputation: 5690
Consider the following:
template <typename TResult> inline TResult _from_string(const string& str);
template <> inline unsigned long long _from_string<unsigned long long>(const string& str) {
return stoull(str);
}
I can call the function as such:
auto x = _from_string<unsigned long long>("12345");
Now I would like to write another specialization for vector
s, i.e.:
template <typename T> inline vector<T> _from_string<vector<T>>(const string& str) {
// stuff that should be done only if the template parameter if a vector of something
}
so that I can do something like this:
auto x = _from_string<vector<int>>("{1,2,3,4,5}");
However, when I compile the function (under MSVC 2015), I get error C2768: "illegal use of explicit template arguments", which makes some sense as I shouldn't be having new template arguments in a specialization.
How can I rewrite the vector
specialization so that it will work?
Upvotes: 1
Views: 114
Reputation: 275966
You cannot partially specialize functions.
You should rarely fully specialize functions.
A far better way to handle this problem is to use overloading. Overloading on return type just requires an extra arg:
template<class T> struct tag_t{constexpr tag_t(){}; using type=T;};
template<class T>constexpr tag_t<T> tag{};
template <typename TResult> inline TResult _from_string(const string& str){
return _from_string( tag<TResult>, str );
}
Now we never specialize _from_string
, we just overload the 2 arg version.
inline unsigned long long _from_string(tag_t<unsigned long long>, const string& str) {
return stoull(str);
}
The above isn't even a template.
template <class T, class A>
std::vector<T,A> _from_string(tag_t<std::vector<T,A>>, const string& str) {
// stuff that should be done only if the target type is a vector of something
}
The above is a template, but not a specialization of one.
As a bonus, if you have a custom type bob
in namespace foo
, you simply have to write _from_string( tag_t<bob>, std::string const& )
in namespace foo
, and something known as 'ADL' will automatically find it in most cases.
Overload based dispatching with tags is clear and simple and lets you customize things in related namespaces.
Upvotes: 3
Reputation: 173044
Function templates can only be full specialized, they can't be partial specialized; but class templates can.
// primary class template
template <typename T>
struct X {
static T _from_string(const string& str);
};
// full specialization for unsigned long long
template <>
struct X<unsigned long long> {
static unsigned long long _from_string(const string& str) {
return stoull(str);
}
};
// partial specialization for vector<T>
template <typename T>
struct X<vector<T>> {
static vector<T> _from_string(const string& str) {
// stuff that should be done only if the template parameter if a vector of something
}
};
// helper function template
template <typename TResult>
inline TResult _from_string(const string& str) {
return X<TResult>::_from_string(str);
}
then
auto x1 = _from_string<unsigned long long>("12345");
auto x2 = _from_string<vector<int>>("{1,2,3,4,5}");
Upvotes: 3