自定义分配器的模板参数推导

Template argument deduction of custom allocator

有一个自定义分配器class:

template<typename T>
class pool_allocator {
public:
    using value_type = T;
    using pointer = value_type *;

    /* Default constructor */
    constexpr pool_allocator( void ) noexcept = default;

    /* Converting constructor used for rebinding */
    template<typename U>
    constexpr pool_allocator( const pool_allocator<U> & ) noexcept {}

    [[nodiscard]] pointer allocate( size_t n, [[maybe_unused]] const pointer hint = nullptr ) const noexcept {
        return get_pool().allocate( n );
    }

    void deallocate( pointer ptr, size_t n ) noexcept {
        get_pool().deallocate( ptr, n );
    }

private:
    template<size_t CAPACITY>
    memory_pool<value_type, CAPACITY> & get_pool( void ) noexcept;
};

pool_allocator 用作 memory_pool 实现的分配器:

template<typename T, size_t CAPACITY>
class memory_pool {
public:
    using element_type = T;
    using pointer = element_type *;
    static constexpr size_t capacity { CAPACITY };

    [[nodiscard]] inline pointer allocate( [[maybe_unused]] size_t n = 1 ) noexcept { ... }

    inline void deallocate( pointer ptr, [[maybe_unused]] size_t n = 1 ) noexcept { ... }
};

问题是对于各种大小的特定类型,存在许多内存池实例。例如:

struct sample { /* ... */ };

memory_pool<sample, 10> m_samples;  /* Serves for 10 instances of 'sample' type */

曾尝试使用 pool_allocatorm_samples 池中分配实例:

allocator_traits<pool_allocator<sample>>::allocate( pool_allocator<sample> {}, 1 );

需要使用分配器“link”具体 memory_pool 实例。让我们考虑一下,类型 T 每次都匹配,但分配器不应知道 memory_pool 容量。所以我的想法是为特定的 memory_pool 类型 get_pool() 声明一个 getter - 在分配器中声明它,但在 .cpp 文件中定义它以实现 link ,类似:

.cpp:

template<> template<>
memory_pool<sample, 10> & pool_allocator<sample>::get_pool( void ) noexcept {
    return m_samples; /* The instance being created before */
}

所以我的问题是:如何实现这个?简单地选择使用类型特定 pool_allocator<sample> 来操作相同类型的具体 memory_pool 实例,但不将容量指定为显式 pool_allocator 模板参数...使其推导?要改用 delegate/function 指针吗?还有其他方法吗?

解决方法很简单(只列出重要部分):

template<typename T>
class pool_allocator {
public:

    [[nodiscard]] pointer allocate( size_t n, [[maybe_unused]] const pointer hint = nullptr ) const noexcept {
        return get_pool().allocate( n );
    }

    void deallocate( pointer ptr, size_t n ) noexcept {
        get_pool().deallocate( ptr, n );
    }

private:
    static auto & get_pool( void ) noexcept; /* <-- here it comes */
};

然后在 .cpp 文件的某处,专门针对特定类型的 get_pool() 静态成员:

template<>
auto & pool_allocator<sample>::get_pool( void ) noexcept {
    return m_samples;
}

如此简单的自动声明就可以了。也许下一步要改进的是用一个概念来约束 get_pool() return 值,但这是另一回事...