关于自定义分配器和 stl 的模板声明、别名和专业化说明

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

抱歉,标题含糊不清,但我不知道哪个是正确的术语(即使可以执行以下操作)。

假设我在某个地方有一个模板 class(一个分配器):

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

然后我有另一个class,它与Allocator有某种关系,但不能在实例化时专门化T参数。 这个想法是为它声明一个 "not specialized alias" ,并让专业化在其他地方。 类似于:

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

   void* Allocate(size_t);
};

用法应该是这样的:

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

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

其背后的主要思想是,由于 stl 容器需要一个针对所包含元素类型的专用分配器,我仍然可以使用相同的内存空间并让专用实例将分配调用转发给它。 但我仍然希望 Arena 本身控制基本分配策略(最终还对未完全专门化的参数进行参数化 AllocatorStrategy)。

有什么提示吗?这可能吗?


编辑

感谢评论,我以这种方式使用别名模板修复了声明:

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

  void* Allocate(size_t);
};

我仍然需要弄清楚是否可以使 Allocator 成为 MemoryArena 定义的一部分,而无需完全指定 T 参数。类似于:

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>;

或者,您也可以提出任何其他建议。主要目标是让用户指定 Arena 的分配器类型,T 参数除外(仅对在容器内使用分配器有用)。

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>
  >;
};

假设除了 DefaultAllocTypeOtherAllocType<Chicken, T> 之外还有其他分配类型。那么:

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

另一方面,如果您要求传递给传入模板的参数是MemoryArena本身有时,事情会变得更加复杂。

MemoryArena参数化前,类型不存在。所以你必须有某种占位符可以告诉你应该在哪里注入它。

如果您希望它始终为 MemoryArena,那么事情就更简单了:您已经有了该解决方案:

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