模板和STL

发布于 2024-10-17 09:06:52 字数 1293 浏览 1 评论 0 原文

以下代码表示基于 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;
}

The following code represents a container based on 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;
}

Is it possible to templatize std::vector and create a general container, something like that?

template <typename Item, typename stl_container>
struct TList
{
    typedef stl_container<Item>;
};

where stl_container represents std::vector, std::list, std::set...? I would like to choose the type of container at the time of the creation.

List <Object, std::vector> list; //vector of objects, not a real code
List <Object, std::vector> list; //list of objects, not a real code

Thanks for your answers...

Updated question:

I tried the following code but there are errors:

#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

花伊自在美 2024-10-24 09:06:52

是的,但不是直接的:

template <typename Item, template <typename> class Container>
struct TList
{
    typedef typename Container<Item>::type type;
};

然后你可以定义不同的容器策略:

template <typename T>
struct vector_container
{
    typedef std::vector<T> type;
};

template <typename T>
struct map_container
{
    typedef std::map<T, std::string> type;
};

TList<int, vector_container> v;
TList<int, map_container> m;

不过有点冗长。*要直接做事情,你需要采取 詹姆斯描述的路线,但正如他指出的那样,这最终非常不灵活。

然而,使用 C++0x,我们可以很好地做到这一点:

#include <map>
#include <vector>

template <typename Item,
            template <typename...> class Container, typename... Args> 
struct TList
{
    // Args lets the user specify additional explicit template arguments
    Container<Item, Args...> storage;
};

int main()
{
    TList<int, std::vector> v;
    TList<int, std::map, float> m;
}

完美。不幸的是,除了通过如上所述引入的间接策略类之外,没有办法在 C++03 中重现这一点。


*我想强调的是,“有点冗长”是指“这是非正统的”。问题的正确解决方案是标准库的做法,正如 Jerry 所解释的。您只需让容器适配器的用户直接指定整个容器类型即可:

template <typename Item, typename Container = std::vector<Item>>
struct TList
{};

但这留下了一个大问题:如果我不希望容器的值类型为 Item 而是 怎么办? some_else?换句话说,如何将现有容器的值类型更改为其他类型?在您的情况下,您不需要,所以不再阅读,但在我们这样做的情况下,我们想要重新绑定一个容器。

对我们来说不幸的是,容器没有这个功能,尽管分配器有:

template <typename T>
struct allocator
{
    template <typename U>
    struct rebind
    {
        typedef allocator<U> type;
    };

    // ...
};

这允许我们在给定分配器的情况下获得一个分配器。如果没有这种侵入性实用程序,我们如何才能对容器做同样的事情呢?在 C++0x 中,这很简单:

template <typename T, typename Container>
struct rebind; // not defined

template <typename T, typename Container, typename... Args>
struct rebind<T, Container<Args...>>
{
    // assumes the rest are filled with defaults**
    typedef Container<T> type; 
};

给定 std::vector,我们可以执行 rebind>::type >,例如。与之前的 C++0x 解决方案不同,这个解决方案可以在 C++03 中使用宏和迭代进行模拟。


**注意,这种机制可以变得更加强大,例如指定要保留哪些参数、要重新绑定哪些参数、要重新绑定哪些参数。在用作参数等之前重新绑定自己,但这留给读者作为练习。 :)

Yes, but not directly:

template <typename Item, template <typename> class Container>
struct TList
{
    typedef typename Container<Item>::type type;
};

Then you can define different container policies:

template <typename T>
struct vector_container
{
    typedef std::vector<T> type;
};

template <typename T>
struct map_container
{
    typedef std::map<T, std::string> type;
};

TList<int, vector_container> v;
TList<int, map_container> m;

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:

#include <map>
#include <vector>

template <typename Item,
            template <typename...> class Container, typename... Args> 
struct TList
{
    // Args lets the user specify additional explicit template arguments
    Container<Item, Args...> storage;
};

int main()
{
    TList<int, std::vector> v;
    TList<int, std::map, float> m;
}

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:

template <typename Item, typename Container = std::vector<Item>>
struct TList
{};

But this leaves a big problem: what if I don't want the value type of the container to be Item but something_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:

template <typename T>
struct allocator
{
    template <typename U>
    struct rebind
    {
        typedef allocator<U> type;
    };

    // ...
};

This allows us to get an allocator<U> given an allocator<T>. How can we do the same for containers without this intrusive utility? In C++0x, it's easy:

template <typename T, typename Container>
struct rebind; // not defined

template <typename T, typename Container, typename... Args>
struct rebind<T, Container<Args...>>
{
    // assumes the rest are filled with defaults**
    typedef Container<T> type; 
};

Given std::vector<int>, we can perform rebind<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. :)

划一舟意中人 2024-10-24 09:06:52

我有点困惑为什么一些非常聪明(并且有能力)的人拒绝。

除非我误读了您的问题,否则您想要完成的任务实际上与标准库中的“容器适配器”相同。每个都提供了一些底层容器类型的接口,并将使用的容器类型作为模板参数(具有默认值)提供。

例如,std::stack 使用一些其他容器(例如,std::dequestd::liststd ::vector)来保存对象,而 std::stack 本身只是在您只想使用堆栈操作时提供了一个简化/限制的接口。 std::stack 将使用的底层容器作为模板参数提供。标准中的代码如下:

namespace std {
    template <class T, class Container = deque<T> >
    class stack {
    public:
        typedef typename Container::value_type value_type;
        typedef typename Container::size_type  size_type;
        typedef Container                      container_type;
    protected:
        Container c;
    public:
        explicit stack(const Container& = Container());
        bool empty() const             { return c.empty(); }
        size_type size() const         { return c.size(); }
        value_type& top()              { return c.back(); }
        const value_type& top() const  { return c.back(); }
        void push(const value_type& x) { c.push_back(x); }
        void pop()                     { c.pop_back(); }
    };
}

当然,也许我只是误解了这个问题——如果是这样,我提前向那些我(有点)不同意的人道歉。

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 or std::vector) to hold the objects, and std::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 the std::stack is provided as a template parameter. Here's how the code looks in the standard:

namespace std {
    template <class T, class Container = deque<T> >
    class stack {
    public:
        typedef typename Container::value_type value_type;
        typedef typename Container::size_type  size_type;
        typedef Container                      container_type;
    protected:
        Container c;
    public:
        explicit stack(const Container& = Container());
        bool empty() const             { return c.empty(); }
        size_type size() const         { return c.size(); }
        value_type& top()              { return c.back(); }
        const value_type& top() const  { return c.back(); }
        void push(const value_type& x) { c.push_back(x); }
        void pop()                     { c.pop_back(); }
    };
}

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.

岁月蹉跎了容颜 2024-10-24 09:06:52

是和不是。

您可以使用模板模板参数,例如,

template <typename Item, template <typename> class Container>
struct TList { /* ... */ };

但是,一般来说,模板模板参数并不是特别有用,因为模板参数的数量和类型必须匹配。因此,上面的内容与 std::vector 不匹配,因为它实际上有两个模板参数:一个用于值类型,另一个用于分配器。模板模板形参不能利用任何默认模板实参。

为了能够使用 std::vector 模板作为参数,TList 必须声明为:

template <typename Item, template <typename, typename> class Container>
struct TList { /* ... */ };

但是,使用此模板,您将无法使用 std::map 模板作为参数,因为它有四个模板参数:键和值类型、分配器类型和比较器类型。

通常,由于这种不灵活性,避免模板模板参数要容易得多。

Yes and no.

You can use a template template parameter, e.g.,

template <typename Item, template <typename> class Container>
struct TList { /* ... */ };

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:

template <typename Item, template <typename, typename> class Container>
struct TList { /* ... */ };

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.

暗喜 2024-10-24 09:06:52

好吧,你可以用宏来破解它:

template <typename T, typename stl_container = std::vector<T> >
struct TList
{
    typedef stl_container Type;
};

#define TLIST(T, C) TList<T, C<T> >

TList<int> foo;
TList<int, std::list<int> > bar;
TLIST(int, std::list) baz;

well, you can hack it up with a macro:

template <typename T, typename stl_container = std::vector<T> >
struct TList
{
    typedef stl_container Type;
};

#define TLIST(T, C) TList<T, C<T> >

TList<int> foo;
TList<int, std::list<int> > bar;
TLIST(int, std::list) baz;
初见你 2024-10-24 09:06:52

是否可以模板化 std::vector 并创建一个通用容器,类似的东西?

不可以。您必须使用容器来模板化函数或对象——您无法模板化容器本身。

例如。考虑一个典型的 std::find :

template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value )
{
    for ( ;first!=last; first++) if ( *first==value ) break;
    return first;
}

这适用于任何容器,但根本不需要容器的模板。

另外,考虑到您想要做的是制作独立于容器的代码,您可能想购买或借用自己的副本 Scott Meyers 的有效 STL 并阅读第 2 条:谨防容器独立代码的错觉。

Is it possible to templatize std::vector and create a general container, something like that?

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:

template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value )
{
    for ( ;first!=last; first++) if ( *first==value ) break;
    return first;
}

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.

送你一个梦 2024-10-24 09:06:52

您可以使用模板模板参数,正如其他人在此处提到的那样。这样做的主要困难不是不同的容器类型具有不同的模板参数,而是标准允许标准容器(如矢量)除了记录的必要参数之外还具有模板参数。

您可以通过提供自己的子类类型来解决这个问题,该子类类型接受适当的模板参数,并让任何额外的内容(必须有默认值)填充在我的实现中:

template < typename T > struct simple_vector : std::vector<T> {};

或者您可以使用模板化的 typedef 习惯用法:

template < typename T > struct retrieve_vector { typedef std::vector<T> type; };

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:

template < typename T > struct simple_vector : std::vector<T> {};

Or you can use the templated typedef idiom:

template < typename T > struct retrieve_vector { typedef std::vector<T> type; };
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文