通常在模板中你想知道整个类型,但在我的情况下我需要知道更多,并希望“分解”类型。举个例子:
template <typename Collection<typename T> >
T get_front(Collection const& c)
{
return c.front();
}
我怎样才能实现这一目标?注意:我需要它来自动推断类型,而不是传递类似<std::vector<int>, int>
答案 0 :(得分:7)
编辑:最后可以找到C ++ 0x方式 编辑2 :我是愚蠢的,并且在答案结束时可以找到比所有这些特征更短的方式更短的C ++ 98/03方式。
如果您希望您的函数适用于任何仲裁标准库容器,则需要提取一些模板枪。
问题是,不同的容器采用不同数量的模板参数。例如,std::vector
,std::deque
和std::list
取2:基础项类型T
和分配器类型Alloc
。另一方面,std::set
和std::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)
我假设你想要Collection
和T
作为模板参数。为此,只需输入
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)
如果可以的话,我会避免使用通用的东西,或者专门使用你知道将要使用的集合的函数,或者特定类的类(如果可能的话)。