另一种奇怪的反复出现的模板模式

时间:2009-09-21 20:25:56

标签: c++ templates f-bounded-polymorphism

template <class Data, class Allocator = std::allocator<Node> >
class Node : public Data {
  // ...
};

问题很简单,如何编译上面的代码? 目的是为Node提供分配其他节点的可能性(以及提供默认分配器)。

5 个答案:

答案 0 :(得分:6)

不能这样写:

template <class Data, class Allocator>
class Node;

template <class Data, class Allocator = 
  std::allocator<Node<Data, std::allocator<Node<...> >
class Node : public Data {
  // ...
};

因为默认参数必须重复。您可以使用标记类型,但

struct DefaultAllocatorTag { };

template<typename Alloc, typename Node>
struct SelectAllocator {
  typedef Alloc type;
};

template<typename Node>
struct SelectAllocator<DefaultAllocatorTag, Node> {
  typedef std::allocator<Node> type;
};

template <class Data, class Allocator = DefaultAllocatorTag >
class Node : public Data {
  typedef typename SelectAllocator<Allocator, Node>::type 
    NodeAllocator;
};

如果适用,我会确定容器中的分配器。像这样:

template<typename Data, typename Allocator = std::allocator<Data> >
struct Container {
  struct Node : Data { 
    typedef typename Allocator::template rebind<Node>::other NodeAllocator;
    ...
  };
  ...
};

答案 1 :(得分:6)

最后我解决了!解决方案是延迟默认分配器的特化,直到已经定义了Node的类的内部:

template <class Data, template<class T> class TAllocator = std::allocator >
class Node : public Data {
  typedef TAllocator<Node> Allocator;
  // ...
};

答案 2 :(得分:2)

这个怎么样?:

#include <memory>

template<class Data>
class NodeImpl : public Data
{
};

template<class Data, class Allocator = std::allocator< NodeImpl<Data> > >
class Node : public NodeImpl<Data>
{
};

class MyAllocator
{
};

class MyDataClass
{
};

int main()
{
    Node<MyDataClass> node;

    Node<MyDataClass, MyAllocator> node_with_alloc;

    return 0;
}

答案 3 :(得分:1)

你不能让它编译 - 你想要创建的是一个“无限”类型。

让我们从那开始,您不能使用未实例化的类模板作为模板参数。所以你需要将Node传递给std :: allocator,如下所示:

template <class Data, class Allocator = std::allocator<Node<Data, Something> > > 
class Node ...

然而,这会是什么?好吧,std :: allocator

诀窍是分配器不仅需要分配模板参数,还需要分配任何其他类型。将您声明为

template <class Data, class Allocator = std::allocator<Data> > class Node ...

然后,为这样的节点创建分配器:

typename Allocator::rebind<Node>::other nodeAllocator(myDataAllocator)

This vcblog post about allocators可能有所帮助,尽管它过于专注于迭代器。

答案 4 :(得分:0)

另一种解决方案。这个似乎更典型。 IE浏览器。矢量和智能指针实现正在使用类似的东西。这个想法是私下继承分配器:

template <class Data, template <class N> class Allocator = std::allocator>
class Node : public Data, private Allocator<Node<Data, Allocator> > {
  // ...
};

奖金是在继承声明中我们已经可以使用Node。