当我们有模板模板参数时,为什么需要allocator :: rebind?

Meh*_*dad 26 c++ templates allocator template-templates

每个allocator类必须具有类似于以下内容的接口:

template<class T>
class allocator
{
    ...
    template<class Other>
    struct rebind { typedef allocator<Other> other; };
};
Run Code Online (Sandbox Code Playgroud)

使用分配器的类做了多余的事情:

template<class T, class Alloc = std::allocator<T> >
class vector { ... };
Run Code Online (Sandbox Code Playgroud)

但为什么这有必要呢?

换句话说,他们不能只是说:

template<class T>
class allocator { ... };

template<class T, template<class> class Alloc = std::allocator>
class vector { ... };
Run Code Online (Sandbox Code Playgroud)

哪个更优雅,更少冗余,(在某些类似的情况下)可能更安全?
他们为什么要走这rebind条路,这也会造成更多的冗余(即你要说T两次)?

(类似的问题char_traits和其他问题......尽管它们并非都有rebind,但它们仍然可以从模板模板参数中受益.)


编辑:

但是,如果您需要多于1个模板参数,这将无效!

实际上,它运作得很好!

template<unsigned int PoolSize>
struct pool
{
    template<class T>
    struct allocator
    {
        T pool[PoolSize];

        ...
    };
};
Run Code Online (Sandbox Code Playgroud)

现在,如果vector只是这样定义:

template<class T, template<class> class Alloc>
class vector { ... };
Run Code Online (Sandbox Code Playgroud)

然后你可以说:

typedef vector<int, pool<1>::allocator> int_vector;
Run Code Online (Sandbox Code Playgroud)

而且它可以很好地工作,而不需要你(冗余地)说int两次.

rebind内部的操作vector只会变成Alloc<Other>而不是Alloc::template rebind<Other>::other.

inc*_*ses 19

来自C++ 11第1卷第4卷第1 期"算法基础"的引用文本.35:

template <typename T> 
struct allocator 
{  
   template <typename U>  
   using  rebind = allocator<U>; 
}; 
Run Code Online (Sandbox Code Playgroud)

样品用量:

allocator<int>::rebind<char> x;
Run Code Online (Sandbox Code Playgroud)

C++ Programming Language,第4版,第34.4.1节,p.998,在默认分配器类中评论"经典"重新绑定成员:

template<typename U>
     struct rebind { using other = allocator<U>;};
Run Code Online (Sandbox Code Playgroud)

Bjarne Stroustrup写道:

好奇的重新绑定模板是一个古老的别名.应该是:

template<typename U>
using other = allocator<U>;
Run Code Online (Sandbox Code Playgroud)

但是,在C++支持这些别名之前定义了分配器.

  • +1 引用 stroustrup,顺便说一下您的链接已断开 (2认同)

Mik*_*son 11

但为什么这有必要呢?

如果你的allocator类有多个模板参数怎么办?

这就是为什么通常不鼓励使用模板模板参数,而不是使用普通模板参数,即使它意味着实例化站点有点冗余.在许多情况下(但可能不适用于分配器),该参数可能并不总是类模板(例如,具有模板成员函数的普通类).

您可能会发现使用模板模板参数很方便(在容器类的实现中),因为它简化了一些内部语法.但是,如果用户有一个多参数类模板作为他想要使用的分配器,但是你需要用户提供一个单参数类模板的分配器,你实际上会迫使他为几乎创建一个包装器.他必须使用该分配器的任何新环境.这不仅不可扩展,它也可能变得非常不方便.而且,在这一点上,该解决方案远不是您最初认为的"优雅且不那么多余"的解决方案.假设您有一个带有两个参数的分配器,以下哪个对用户来说最简单?

std::vector<T, my_allocator<T,Arg2> > v1;

std::vector<T, my_allocator_wrapper<Arg2>::template type > v2;
Run Code Online (Sandbox Code Playgroud)

你基本上强迫用户构造很多无用的东西(包装器,模板别名等)只是为了满足你的实现需求.要求自定义分配器类的作者提供嵌套的重新绑定模板(这只是一个简单的模板别名)比使用替代方法所需的所有扭曲要容易得多.


Dav*_*eas 5

在您的方法中,您将强制分配器成为具有单个参数的模板,但情况并非总是如此。在许多情况下,分配器可以是非模板的,并且嵌套rebind可以返回相同类型的分配器。在其他情况下,分配器可以具有额外的模板参数。第二种情况是这样的 std::allocator<>,因为只要实现提供默认值,标准库中的所有模板都允许具有额外的模板参数。还要注意,rebind在某些情况下,的存在是可选的,allocator_traits可以用来获取回弹类型。

该标准实际上提到嵌套rebind实际上只是一个模板化的typedef:

§17.6.3.5/ 3注A:上表中重新绑定的成员类模板实际上是typedef模板。[注:一般来说,如果分配器被绑定到名称SomeAllocator<T>,然后 Allocator::rebind<U>::other是相同的类型SomeAllocator<U>,其中 someAllocator<T>::value_type是T和SomeAllocator<U>::value_type是U. -注完如果分配器是以下形式的类模板实例SomeAllocator<T, Args>,其中参数数量是零个或多个类型参数,并且Allocator不提供重新绑定成员模板,默认情况下使用标准allocator_traits模板SomeAllocator<U, Args>代替Allocator:: rebind<U>::other。对于不是上述形式的模板实例化的分配器类型,没有提供默认值。