如何“模式匹配”模板?

时间:2011-03-26 02:57:15

标签: c++ templates

通常在模板中你想知道整个类型,但在我的情况下我需要知道更多,并希望“分解”类型。举个例子:

template <typename Collection<typename T> >
T get_front(Collection const& c)
{
  return c.front();
}

我怎样才能实现这一目标?注意:我需要它来自动推断类型,而不是传递类似<std::vector<int>, int>

的内容

4 个答案:

答案 0 :(得分:7)

编辑:最后可以找到C ++ 0x方式 编辑2 :我是愚蠢的,并且在答案结束时可以找到比所有这些特征更短的方式更短的C ++ 98/03方式。

如果您希望您的函数适用于任何仲裁标准库容器,则需要提取一些模板枪。


问题是,不同的容器采用不同数量的模板参数。例如,std::vectorstd::dequestd::list取2:基础项类型T和分配器类型Alloc。另一方面,std::setstd::map分别取3和4:两者都具有键类型K,map采用另一个值类型V,然后两者都采用比较器{{ 1}}类型和分配器类型Compare。您可以概述标准库提供的所有容器类型,例如here


现在,对于模板枪。我们将使用部分专业的traits metastruct来获取基础项类型。 (我使用Alloc代替class而不是纯粹的偏好。)

typename

现在准备就绪了,进入template<class T> struct ContainerTraits; // vector, deque, list and even stack and queue (2 template parameters) template< template<class, class> class Container, class T, class Other > struct ContainerTraits< Container<T,Other> >{ typedef T value_type; }; // for set, multiset, and priority_queue (3 template parameters) template< template<class, class, class> class Container, class T, class Other1, class Other2 > struct ContainerTraits< Container<T,Other1,Other2> >{ typedef T value_type; }; // for map and multimap (4 template parameters) template< template<class, class, class, class> class Container, class Key, class T, class Other1, class Other2 > struct ContainerTraits< Container<Key,T,Other1,Other2> >{ typedef Container<Key,T,Other1,Other2> ContainerT; // and the map returns pair<const Key,T> from the begin() function typedef typename ContainerT::value_type value_type; }; 功能!

get_front

唷!就是这样!可以看到一个完整的例子on Ideone。当然,有可能进一步优化,返回映射到template<class Container> typename ContainerTraits<Container>::value_type get_front(Container const& c){ // begin() is the only shared access function // to the first element for all standard container (except std::bitset) return *c.begin(); } 中的键的实际值,或使用特定于容器的访问函数,但我只是有点懒得去做。 :P


修改
方式更容易C ++ 0x方式使用新的trailing-return-type函数语法,其中一个示例可以找到here on Ideone


编辑2
好吧,我不知道为什么,但在写这个答案时我完全没有想到嵌​​套的std::map。我会让详细的方式作为特征类/模式匹配模板的参考。 This是这样做的方式,它与我对traits类的基本相同,但最终不那么冗长。

答案 1 :(得分:3)

我假设你想要CollectionT作为模板参数。为此,只需输入

即可
template< template < typename > class Collection, typename T >
T get_front( Collection< T > const& c )
...

构造template < typename > class Collection告诉编译器Collection是一个带有一个参数的模板。

修改: 正如Xeo指出的那样,vector有两个模板参数,你的模板需要反映出来,即

template< template < typename, typename > class Collection, 
          typename T, typename Alloc >
T get_front( Collection< T, Alloc > const& c )
...

答案 2 :(得分:2)

如果你知道它不是一个关联容器,你可以这样做。

template <typename Collection>
Collection::type_name get_front(Collection const& c)
{
  return c.front();
}

答案 3 :(得分:0)

看到Collection<T>提前知道,我想你想要的是:

template <typename T>
T get_front(Collection<T> const& c)
{
    return c.front();
}

正在改变的唯一部分是T,它始终位于Collection(内容,而不是容器)中,因此您没有将其作为模板的一部分。

如果容器正在更改,使用c.front()可能会很危险。您需要验证集合类型是否具有不带参数的方法front并返回T

修改

如果你确实需要模板Collection,那就更像是:

template<typename C, typename T>
T get_front(C<T> const & c)

如果可以的话,我会避免使用通用的东西,或者专门使用你知道将要使用的集合的函数,或者特定类的类(如果可能的话)。