如何声明模板函数采用具有已知模板参数类型的模板模板参数?

时间:2014-04-02 14:05:03

标签: c++ templates

我有以下两个功能:

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'

如何正确声明上述模板功能?

3 个答案:

答案 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::vectorstd::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)