模板和STL

Rob*_*obo 5 c++ templates 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;
}
Run Code Online (Sandbox Code Playgroud)

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

template <typename Item, typename stl_container>
struct TList
{
    typedef stl_container<Item>;
};
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

谢谢你的回答......

更新的问题:

我尝试了以下代码,但有错误:

#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;
}
Run Code Online (Sandbox Code Playgroud)

GMa*_*ckG 11

是的,但不是直接:

template <typename Item, template <typename> class Container>
struct TList
{
    typedef typename Container<Item>::type type;
};
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

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

但是,使用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;
}
Run Code Online (Sandbox Code Playgroud)

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


*我想强调一点,"有点啰嗦",我的意思是"这是非正统的".Jerry解释说,正确解决问题的方法就是标准库所做的事情.您只需让容器适配器的用户直接指定整个容器类型:

template <typename Item, typename Container = std::vector<Item>>
struct TList
{};
Run Code Online (Sandbox Code Playgroud)

但是,这留下了很大的问题:如果我不想容器的值类型为Item,但something_else<Item>?换句话说,如何将现有容器的值类型更改为其他容器?在你的情况下,你没有,所以不要再读,但在我们这样做的情况下,我们想重新绑定一个容器.

对我们来说不幸的是,虽然分配器执行以下操作,但容器没有此功能:

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

    // ...
};
Run Code Online (Sandbox Code Playgroud)

这允许我们得到一个allocator<U>给定的allocator<T>.如果没有这种侵入性实用工具,我们如何才能对容器做同样的事情?在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; 
};
Run Code Online (Sandbox Code Playgroud)

鉴于std::vector<int>,我们可以执行rebind<float, std::vector<int>>::type,例如.与以前的C++ 0x解决方案不同,这个解决方案可以在C++ 03中使用宏和迭代进行仿真.


**注意这个机制可以变得更加强大,比如指定要保留哪些参数,重新绑定哪些参数,在用作参数之前重新绑定哪些参数等等,但这仍然是读者的练习.:)


Jer*_*fin 6

我有点困惑为什么一些非常聪明(和称职)的人说不.

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

例如,std::stack使用一些其他的容器(如std::deque,std::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(); }
    };
}
Run Code Online (Sandbox Code Playgroud)

当然,也许我只是误解了这个问题 - 如果是这样的话,我会事先向那些我(有点)不同意的人道歉.


Jam*_*lis 5

是的,不是.

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

template <typename Item, template <typename> class Container>
struct TList { /* ... */ };
Run Code Online (Sandbox Code Playgroud)

但是,通常,模板模板参数不是特别有用,因为模板参数的数量和类型必须匹配.因此,上面的内容不匹配,std::vector因为它实际上有两个模板参数:一个用于值类型,另一个用于分配器.模板模板参数无法利用任何默认模板参数.

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

template <typename Item, template <typename, typename> class Container>
struct TList { /* ... */ };
Run Code Online (Sandbox Code Playgroud)

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

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