问题描述
通常在模板中你想知道整个类型,但在我的情况下,我需要知道更多,并希望分手的类型。以这个例子:
template< typename Collection< typename T> >
T get_front(Collection const& c)
{
return c.front();
}
如何实现?注意:我需要它来自动推导类型,不传递< std :: vector< int>,int>
编辑:可以在结尾找到C ++ 0x方式。
2 :我很蠢,并且缩短C ++ 98/03比所有这些traits的东西可以在答案的最后找到。
如果您希望您的函数适用于任何标准库容器,您需要提取一些模板枪。
事情是,不同的容器采用不同数量的模板参数。 std :: vector
, std :: deque
与 std :: list
例如take 2:底层项类型 T
和分配器类型 Alloc
。 std :: set
和 std :: map
另一方面分别取3和4: K
,map采用另一个值类型 V
,则两个比较器比较
类型和分配器类型 Alloc
。您可以获得标准库提供的所有容器类型的概述,例如。 p>
现在,对于模板枪。我们将使用一个部分专用的traits元结构来获取基础项目类型。 (我使用 class
而不是 typename
纯粹的偏好。)
模板< class T>
struct ContainerTraits;
//向量,deque,列表甚至栈和队列(2个模板参数)
template<
template< class,class> class Container,
class T,class Other
>
struct ContainerTraits<容器< T,其他> > {
typedef T val_type;
};
//用于set,multiset和priority_queue(3个模板参数)
template<
template< class,class,class> class Container,
class T,class Other1,class Other2
>
struct ContainerTraits<集装箱< T,其他1,其他2> > {
typedef T value_type;
};
//用于map和multimap(4个模板参数)
模板<
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;
//并且映射返回pair< const Key,T>从begin()函数
typedef typename ContainerT :: value_type value_type;
};
现在准备工作已完成,到 get_front
function!
template< class Container>
typename ContainerTraits< Container> :: value_type
get_front(Container const& c){
// begin()是唯一的共享访问函数
//到第一个元素所有标准容器(除std :: bitset)
return * c.begin();
}
就是这样!有关完整示例,请参阅。当然,有可能进一步细化,以返回映射到 std :: map
中的键的实际值,或者使用容器特定访问功能,但我只是有点太懒了做到这一点。 :P
编辑
更容易C ++ 0x方式使用新的trailing-return-type函数语法,其中的一个示例可以在。
编辑2
好,我不知道为什么,但我完全没有想到嵌套的 typedef
在写这个答案。我将让详细的方式作为traits类/模式匹配模板的参考。 的方式,它基本上与traits类相同,但最终不那么冗长。
Normally in templates you want to know the entire type, but in my case I need to know more, and want to "break up" the type. Take this example:
template <typename Collection<typename T> >
T get_front(Collection const& c)
{
return c.front();
}
How can I achieve that? Note: I need it to to automatically deduce the types, not pass in something like <std::vector<int>, int>
Edit: A C++0x way can be found at the end.
Edit 2: I'm stupid, and a way shorter C++98/03 way than all this traits stuff can be found at the end of the answer.
If you want your function to work for any arbitary standard library container, you need to pull out some Template Guns.
The thing is, that the different container take a different amount of template parameters. std::vector
, std::deque
and std::list
for example take 2: the underlying item type T
and the allocator type Alloc
. std::set
and std::map
on the other hand take 3 and 4 respectively: both have the key type K
, map takes another value type V
, then both take a comparator Compare
type and the allocator type Alloc
. You can get an overview of all container types supplied by the standard library for example here.
Now, for the Template Guns. We will be using a partially specialized traits metastruct to get the underlying item type. (I use class
instead of typename
out of pure preference.)
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;
};
Now that the preparation is done, on to the get_front
function!
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();
}
Phew! And that's it! A full example can be seen on Ideone. Of course it would be possible to refine that even further, to the point of returning the actual value that is mapped to a key in a std::map
, or use container specific access functions, but I was just a bit too lazy to do that. :P
Edit
A way easier C++0x way is using the new trailing-return-type function syntax, of which an example can be found here on Ideone.
Edit 2
Well, I don't know why, but I totally didn't think of the nested typedef
s when writing this answer. I'll let the verbose way stay as a reference for traits classes / pattern matching a template. This is the way to do it, it is basically the same I did with the traits classes, but ultimately less verbose.
这篇关于如何“模式匹配”模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!