Another curious repeating pattern
You cannot write it like this:
template <class Data, class Allocator>
class Node;
template <class Data, class Allocator =
std::allocator<Node<Data, std::allocator<Node<...> >
class Node : public Data {
// ...
};
Because the default argument is to repeat itself. You can use tag-type though
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;
};
If applicable, I would define an allocator in a container. Like this:
template<typename Data, typename Allocator = std::allocator<Data> >
struct Container {
struct Node : Data {
typedef typename Allocator::template rebind<Node>::other NodeAllocator;
...
};
...
};
source to share
template <class Data, template<class T> class TAllocator = std::allocator >
class Node : public Data {
typedef TAllocator<Node> Allocator;
// ...
};
source to share
How about this ?:
#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;
}
source to share
You cannot compile it - what you are trying to create is an "infinite" type.
To begin with, you cannot use an uninstalled template template as a template argument. So you need to pass Node to std :: allocator like:
template <class Data, class Allocator = std::allocator<Node<Data, Something> > >
class Node ...
However, what would it be? Well, std :: allocator
The trick is that allocators have to allocate not only the template argument, but any other type as well. Declare the class as
template <class Data, class Allocator = std::allocator<Data> > class Node ...
Then create an allocator for nodes like this:
typename Allocator::rebind<Node>::other nodeAllocator(myDataAllocator)
This vcblog post about allocators could help, although it focused too much on iterators.
source to share
Another solution. This seems to be more typical. I.e. the implementation of vectors and smart pointers uses something similar. The idea is to privately inherit from an allocator:
template <class Data, template <class N> class Allocator = std::allocator>
class Node : public Data, private Allocator<Node<Data, Allocator> > {
// ...
};
The bonus is that we can already use Node.
source to share