I try to write a custom STL-style container. For the sake of simplicity, let's say it's a list. I looked up the standard way to define such a container:
template <typename T, typename A = std::allocator<T> > class mylist;
Now, I want to manage the nodes of the list using a nested class:
(inside mylist)
class node {
    T data;
    node *next;
}
It is my understanding that I need not put a template specifier in front of the definition of node as the compiler will instantiate separate classes mylist<T,A>::node for each combination of mylist's template parameters.
However, now I need to allocate memory not only for the data of type T itself, but also for their wrapper node. Thus, I would like the default template parameter to be of type std::allocator<mylist<T>::node>. At that point, though, mylist has not yet been declared and the compiler is understandably upset:
error: `mylist' was not declared in this scope
How would one resolve this conundrum? There are two constraints:
node to be nested as it needs to access the allocator instance of mylist. E.g., I have operator= declared on node where a lot of memory management happens recursively. This might be overkill for a list and you could do that from within mylist, thereby dropping the parametric dependence of node on A, but it is crucial for the data structure I'm implementing. It doesn't matter what the default allocator's type argument is, just the actual type. You can use rebind_alloc from std::allocator_traits:
Alloc::rebind<T>::otherif present, otherwiseAlloc<T, Args>if thisAllocisAlloc<U, Args>
to get what you need:
template <typename T, typename A = std::allocator<T> >
class mylist {
    class node { ... };
    using NodeAlloc = typename std::allocator_traits<A>::template rebind_alloc<node>;
};
And then use NodeAlloc to get your nodes. In this way, if the user doesn't specify an allocator, you would get the default std::allocator<T> and then use std::allocator<node>. This is precisely what you want, without having to expose node.
I need node to be nested as it needs to access the allocator instance of
mylist
Don't be so sure. They can be friends:
template <typename, class> class list;
template <typename T>
struct node {
    // ...
};
template <typename T, class Alloc=std::allocator<T> >
class list {
    friend node<T>;
    // ...
};
If you don't want node to be accessible outside of your file, just omit it in your header file (.h / .hpp).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With