特定模板类型的功能特化
Specialization of function for a specific template type
考虑以下因素:
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:"illegal use of explicit template arguments",这是有道理的,因为我不应该在专业化中使用新的模板参数。
我如何重写 vector
专业化以使其正常工作?
函数模板只能是full specialized, they can't be partial specialized;但 class 个模板可以。
// 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}");
您不能部分特化函数。
你应该很少完全专门化函数。
处理此问题的更好方法是使用重载。 return 类型的重载只需要一个额外的参数:
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
}
以上是一个模板,不是模板的特化。
作为奖励,如果您在 namespace foo
中有自定义类型 bob
,您只需在 namespace foo
中编写 _from_string( tag_t<bob>, std::string const& )
,以及称为 'ADL'在大多数情况下会自动找到它。
带标签的基于重载的调度清晰简单,让您可以自定义相关命名空间中的内容。
考虑以下因素:
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:"illegal use of explicit template arguments",这是有道理的,因为我不应该在专业化中使用新的模板参数。
我如何重写 vector
专业化以使其正常工作?
函数模板只能是full specialized, they can't be partial specialized;但 class 个模板可以。
// 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}");
您不能部分特化函数。
你应该很少完全专门化函数。
处理此问题的更好方法是使用重载。 return 类型的重载只需要一个额外的参数:
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
}
以上是一个模板,不是模板的特化。
作为奖励,如果您在 namespace foo
中有自定义类型 bob
,您只需在 namespace foo
中编写 _from_string( tag_t<bob>, std::string const& )
,以及称为 'ADL'在大多数情况下会自动找到它。
带标签的基于重载的调度清晰简单,让您可以自定义相关命名空间中的内容。