Bernard
Bernard

Reputation: 5690

Specialization of function for a specific template type

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 vectors, 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

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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

songyuanyao
songyuanyao

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}");

LIVE

Upvotes: 3

Related Questions