2017-01-14 4 views
1

Рассмотрим следующее:Специализация функции для определенного типа шаблона

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

я могу вызвать функцию как таковую:

auto x = _from_string<unsigned long long>("12345"); 

Теперь я хотел бы написать еще одну специализацию vector с, т.е. :

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 
} 

так, что я могу сделать что-то вроде этого:

auto x = _from_string<vector<int>>("{1,2,3,4,5}"); 

Однако при компиляции функции (под MSVC 2015), я получаю C2768 ошибки: «незаконное использование аргументов явного шаблона», что делает какой-то смысл, как я не должен быть с новыми аргументами шаблона в специализации ,

Как переписать специализацию vector так, чтобы она работала?

+0

Herb Sutter обязательно должен прочитать [эту статью] (http://www.gotw.ca/publications/mill17.htm). – Rakete1111

ответ

3

Функциональные шаблоны могут быть только full specialized, их не может быть partial specialized; но шаблоны классов могут.

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

затем

auto x1 = _from_string<unsigned long long>("12345"); 
auto x2 = _from_string<vector<int>>("{1,2,3,4,5}"); 

LIVE

3

Вы не можете частично специализировать функции.

Вы редко должны полностью специализировать функции.

Далеко более эффективный способ справиться с этой проблемой - использовать перегрузку. Перегрузки на тип возвращаемого только требует дополнительного 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); 
} 

Теперь мы никогда не специализироваться _from_string, мы просто перегрузить версию 2 ARG.

inline unsigned long long _from_string(tag_t<unsigned long long>, const string& str) { 
    return stoull(str); 
} 

Вышесказанное не является даже шаблоном.

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 
} 

Вышеупомянутый шаблон, но не специализация.

В качестве бонуса, если у вас есть пользовательский тип bob в namespace foo, вы просто должны написать _from_string(tag_t<bob>, std::string const&) в namespace foo, и что-то известное как «АДЛ» автоматически найти его в большинстве случаев.

Перегрузка, основанная на отправке с тегами, понятна и проста и позволяет настраивать вещи в связанных пространствах имен.

Смежные вопросы