我有以下两个功能:
class Leaf {...};
void SpitLeaves(std::string & sdata, std::vector<Leaf> const & leaves);
void SpitLeaves(std::string & sdata, std::set<Leaf> const & leaves);
这些功能的定义是相同的。
这显然是对函数进行模板化的候选人。
然而,尽管进行了搜索,但我无法弄清楚如何正确声明模板功能。从https://stackoverflow.com/a/4697356/368896和其他人那里,我尝试过签名,例如:
template <template<typename> class T>
void SpitLeaves(std::string & sdata, T<Leaf> const & leaves)
{...}
但是,这会在我尝试实例化模板函数时产生编译器错误:
std::string leaves_str;
std::vector<Leaf> leaves;
SpitLeaves<std::vector>(leaves_str, leaves);
......错误(VS 2013)为'SpitLeaves' : template parameter list for class template 'std::vector' does not match template parameter list for template template parameter 'T'
。
如何正确声明上述模板功能?
答案 0 :(得分:4)
在C ++ 11中,您可以使用可变参数模板模板参数:
template <template<typename...> class T>
void SpitLeaves(std::string & sdata, T<Leaf> const & leaves)
现在编译器不关心T可以采用多少模板参数,只要T<Leaf>
可以实例化。
如果您确实希望支持具有零个或多个额外显式模板参数的容器(例如自定义分配器),则可以这样做:
template <template<typename...> class T, typename... TX>
void SpitLeaves(std::string & sdata, T<Leaf, TX...> const & leaves)
答案 1 :(得分:3)
你可以选择:
template<typename Container>
void SpitLeaves(std::string & sdata, Container const & leaves) { ... }
这样称呼:
std::vector<Leaf> leaves;
SpitLeaves("leaves", leaves); // template argument not necessary
模板模板方法的问题是容器可能只需要一个参数。例如vector
takes two:要存储的元素类型和要使用的分配器。所以为了工作,你需要这个:
template< template<typename,typename> class T, typename A >
void SpitLeaves(std::string & sdata, T<Leaf,A> const & leaves) { ... }
如果您使用泛型类型Container
,则只能使用容器,如果与您的函数不兼容,编译器会抱怨。
答案 2 :(得分:1)
std::vector
和std::set
包含多个模板参数。
所以你应该使用类似的东西:
template <template<typename...> class C, typename ... Args>
void SpitLeaves(std::string & sdata, const C<Leaf, Args...>& leaves)
另一种方法是取容器,并使用SFINAE限制以更正类型:
template <typename C>
typename std::enable_if<std::is_same<Leaf, typename C::value_type>::value>::type
SpitLeaves(std::string & sdata, const C& leaves)