模板和STL
以下代码表示基于 std::vector 的容器
template <typename Item>
struct TList
{
typedef std::vector <Item> Type;
};
template <typename Item>
class List
{
private
typename TList <Item>::Type items;
....
}
int main()
{
List <Object> list;
}
是否可以模板化 std::vector 并创建一个通用容器,类似的东西?
template <typename Item, typename stl_container>
struct TList
{
typedef stl_container<Item>;
};
其中 stl_container 代表 std::vector、std::list、std::set...?我想在创建时选择容器的类型。
List <Object, std::vector> list; //vector of objects, not a real code
List <Object, std::vector> list; //list of objects, not a real code
感谢您的回答...
更新的问题:
我尝试了以下代码,但出现错误:
#include <vector>
template <typename Item, typename Container>
struct TList
{
typedef typename Container <Item>::type type; //Error C2059: syntax error : '<', Error C2238: unexpected token(s) preceding ';
};
template <typename T>
struct vector_container
{
typedef std::vector<T> type;
};
int _tmain(int argc, _TCHAR* argv[])
{
TList <int, vector_container> v;
TList <int, map_container> m;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
是的,但不是直接的:
然后你可以定义不同的容器策略:
不过有点冗长。*要直接做事情,你需要采取 詹姆斯描述的路线,但正如他指出的那样,这最终非常不灵活。
然而,使用 C++0x,我们可以很好地做到这一点:
完美。不幸的是,除了通过如上所述引入的间接策略类之外,没有办法在 C++03 中重现这一点。
*我想强调的是,“有点冗长”是指“这是非正统的”。问题的正确解决方案是标准库的做法,正如 Jerry 所解释的。您只需让容器适配器的用户直接指定整个容器类型即可:
但这留下了一个大问题:如果我不希望容器的值类型为
Item
而是怎么办? some_else
?换句话说,如何将现有容器的值类型更改为其他类型?在您的情况下,您不需要,所以不再阅读,但在我们这样做的情况下,我们想要重新绑定一个容器。对我们来说不幸的是,容器没有这个功能,尽管分配器有:
这允许我们在给定
分配器
的情况下获得一个分配器
。如果没有这种侵入性实用程序,我们如何才能对容器做同样的事情呢?在 C++0x 中,这很简单:给定
std::vector
,我们可以执行rebind>::type
>,例如。与之前的 C++0x 解决方案不同,这个解决方案可以在 C++03 中使用宏和迭代进行模拟。**注意,这种机制可以变得更加强大,例如指定要保留哪些参数、要重新绑定哪些参数、要重新绑定哪些参数。在用作参数等之前重新绑定自己,但这留给读者作为练习。 :)
Yes, but not directly:
Then you can define different container policies:
A bit verbose, though.* To do things directly, you'd need to take the route described by James, but as he notes this is ultimately very inflexible.
However, with C++0x we can do this just fine:
Perfect. Unfortunately there's no way to reproduce this in C++03, except via the indirection policy classes introduce as described above.
*I want to emphasize that by "A bit verbose" I mean "this is unorthodox". The correct solution for your problem is what the standard library does, as Jerry explains. You just let the user of your container adapter specify the entire container type directly:
But this leaves a big problem: what if I don't want the value type of the container to be
Item
butsomething_else<Item>
? In other words, how can I change the value type of an existing container to something else? In your case you don't, so read no further, but in the case we do, we want to rebind a container.Unfortunately for us, the containers don't have this functionality, though allocators do:
This allows us to get an
allocator<U>
given anallocator<T>
. How can we do the same for containers without this intrusive utility? In C++0x, it's easy:Given
std::vector<int>
, we can performrebind<float, std::vector<int>>::type
, for example. Unlike the previous C++0x solution, this one can be emulated in C++03 with macros and iteration..**Note this mechanism can be made much more powerful, like specifying which arguments to keep, which to rebind, which to rebind themselves before using as arguments, etc., but that's left as an exercise for the reader. :)
我有点困惑为什么一些非常聪明(并且有能力)的人拒绝。
除非我误读了您的问题,否则您想要完成的任务实际上与标准库中的“容器适配器”相同。每个都提供了一些底层容器类型的接口,并将使用的容器类型作为模板参数(具有默认值)提供。
例如,
std::stack
使用一些其他容器(例如,std::deque
、std::list
或std ::vector
)来保存对象,而std::stack
本身只是在您只想使用堆栈操作时提供了一个简化/限制的接口。std::stack
将使用的底层容器作为模板参数提供。标准中的代码如下:当然,也许我只是误解了这个问题——如果是这样,我提前向那些我(有点)不同意的人道歉。
I'm a bit puzzled why some very smart (and competent) people are saying no.
Unless I've misread your question, what you're trying to accomplish is virtually identical to the "container adapters" in the standard library. Each provides an interface to some underlying container type, with the container type that will be used provided as a template parameter (with a default value).
For example, a
std::stack
uses some other container (e.g.,std::deque
,std::list
orstd::vector
) to hold the objects, andstd::stack
itself just provides a simplified/restricted interface for when you just want to use stack operations. The underlying container that will be used by thestd::stack
is provided as a template parameter. Here's how the code looks in the standard:Of course, perhaps I've just misunderstood the question -- if so, I apologize in advance to the people with whom I'm (sort of) disagreeing.
是和不是。
您可以使用模板模板参数,例如,
但是,一般来说,模板模板参数并不是特别有用,因为模板参数的数量和类型必须匹配。因此,上面的内容与
std::vector
不匹配,因为它实际上有两个模板参数:一个用于值类型,另一个用于分配器。模板模板形参不能利用任何默认模板实参。为了能够使用
std::vector
模板作为参数,TList
必须声明为:但是,使用此模板,您将无法使用 std::map 模板作为参数,因为它有四个模板参数:键和值类型、分配器类型和比较器类型。
通常,由于这种不灵活性,避免模板模板参数要容易得多。
Yes and no.
You can use a template template parameter, e.g.,
However, in general, template template parameters are not particularly useful because the number and types of the template parameters have to match. So, the above would not match
std::vector
because it actually has two template parameters: one for the value type and one for the allocator. A template template parameter can't take advantage of any default template arguments.To be able to use the
std::vector
template as an argument,TList
would have to be declared as:However, with this template, you wouldn't be able to use the
std::map
template as an argument because it has four template parameters: the key and value types, the allocator type, and the comparator type.Usually it is much easier to avoid template template parameters because of this inflexibility.
好吧,你可以用宏来破解它:
well, you can hack it up with a macro:
不可以。您必须使用容器来模板化函数或对象——您无法模板化容器本身。
例如。考虑一个典型的 std::find :
这适用于任何容器,但根本不需要容器的模板。
另外,考虑到您想要做的是制作独立于容器的代码,您可能想购买或借用自己的副本 Scott Meyers 的有效 STL 并阅读第 2 条:谨防容器独立代码的错觉。
No. You would have to templatize the function or object using the container -- you couldn't templatize the container itself.
For example. consider a typical
std::find
:This works for any container, but doesn't need a tempalte with the container at all.
Also, given that it looks what you're trying to do is make container independent code, you might want to buy or borrow yourself a copy of Scott Meyers' Effective STL and read Item 2: Beware the illusion of container-independent code.
您可以使用模板模板参数,正如其他人在此处提到的那样。这样做的主要困难不是不同的容器类型具有不同的模板参数,而是标准允许标准容器(如矢量)除了记录的必要参数之外还具有模板参数。
您可以通过提供自己的子类类型来解决这个问题,该子类类型接受适当的模板参数,并让任何额外的内容(必须有默认值)填充在我的实现中:
或者您可以使用模板化的 typedef 习惯用法:
You can use template template parameters as others have mentioned here. The main difficulty with this is not that dissimilar container types have dissimilar template parameters, but that the standard allows the standard containers, like vector, to have template parameters in addition to the documented, necessary ones.
You can get around this by providing your own subclass types that accept the appropriate template parameters and let any extras (which have to have defaults) be filled in my the implementation:
Or you can use the templated typedef idiom: