Clarification in template declaration, alias and specialization in regards to custom allocators and stl

112 views Asked by At

Sorry for the vague title, but I don't know exactly which is the correct term (and even if it's possible to do the following).

Let's say I have somewhere a template class (an allocator):

template<class Arena, typename T> Allocator
{
  public:
     Allocator(Arena a);
...
};

Then I have another class, which is in some kind of relation with Allocator, but can't specialize T param in instantiation. The idea is declare a "not specialized alias" for it, and let the specialization be somewhere else. Something like:

class MemoryArena
{
   using Allocator<T> = AnAllocatorStrategy<T>; //not legal, but just to give the idea

   void* Allocate(size_t);
};

The usage should be something like:

Arena anArena(...);
Arena::Allocator<int> allocInt; // some way declare a specialization of the alias

std::vector<int, Arena::Allocator<int>> myVec(allocInt);

The main idea behind that, is that because of stl container need a specialized allocator on the contained element's type, I can still use the same memory arena and let the specialized instances to forward the allocate call to it. But I still would like that is the Arena itself controlling the base allocation strategy (eventually also parametrazing the not completely specialized AllocatorStrategy ).

Any hint on this? Is this possible?


EDIT

Thanks to the comment I fixed the declaration using alias templates this way:

class MemoryArena
{
   template<typename T> using MyAllocatorTemplate = Allocator<MemoryArena, T>;;

  void* Allocate(size_t);
};

I still need to figure out if it's possible make Allocator be part of MemoryArena definition, without fully specify T parameter. Something like:

template<class AllocatorType<MemoryArena,?> = DefaultAllocType<MemoryArena,?>> //is possible not to specify T on MemoryArena definition?
class MemoryArena<AllocatorType>
{
   template<typename T> using MyAllocatorTemplate = AllocatorType<MemoryArena,T>;

Alternatively, any other suggestion is appreciated. The main goal is to let the user specify the Arena's allocator type except for the T parameter (useful only for using the allocator inside containers).

1

There are 1 answers

2
Yakk - Adam Nevraumont On BEST ANSWER
template<template<class...>class Z, class...T0s>
struct partial_apply {
  template<class...T1s>
  using result = Z<T0s...,T1s...>;
};
template<template<class...>class A, template<class...>class B>
struct same_template : std::false_type {};
template<template<class...>class A>
struct same_template<A,A> : std::true_type {};

template<class...>class Default {};
template<
  template<class...>class AllocatorType=Default
>
class MemoryArena {
  template<class T>
  using MyAllocatorTemplate = std::conditional_t<
    same_template<AllocatorType, Default>{},
    DefaultAllocType<MemoryArena, T>,
    AllocatorType<T>
  >;
};

suppose there is some other alloc type besides DefaultAllocType, OtherAllocType<Chicken, T>. Then:

template<class...Ts>
using OtherAllocChicken = partial_apply<OtherAllocType, Chicken>::template result<Ts...>;
using ChickenArena = MemoryArena< OtherAllocChicken >;

on the other hand, if you require that the argument passed to the incoming template be MemoryArena itself sometimes, things get more complex.

Before MemoryArena is parameterized, the type doesn't exist. So you have to have some kind of placeholder that can tell you where you should inject it.

If you want it to always be MemoryArena, then things are easier: you already have that solution:

template<template<class...>class AllocatorType = DefaultAllocType>
class MemoryArena {
  template<typename T>
  using MyAllocatorTemplate = AllocatorType<MemoryArena,T>;
};