没有可变参数模板的通用分配器类?

时间:2010-04-08 13:55:38

标签: c++ templates variadic allocator

我正在尝试编写一个通用的allocator类,当它是free()时,它并没有真正释放对象的内存,而是将它保存在队列中,并在请求新的对象时返回先前分配的对象。现在,我无法解决的问题是如何在使用我的分配器时将参数传递给对象的构造函数(至少不使用可变参数模板)。我想出的alloc()函数如下所示:

template <typename... T>
inline T *alloc(const &T... args) {
    T *p;

    if (_free.empty()) {
        p = new T(args...);
    } else {
        p = _free.front();
        _free.pop();

        // to call the ctor of T, we need to first call its DTor
        p->~T();
        p = new( p ) T(args...);
    }
    return p;
}

但是,我需要代码与今天的C ++(以及不支持可变参数模板的旧版GCC)兼容。有没有其他方法可以将任意数量的参数传递给对象构造函数?

2 个答案:

答案 0 :(得分:3)

当您需要定位预C ++ 0x编译器时,您需要提供伪可变参数模板,即您需要为每个需要的arity提供模板函数:

template<class T> 
T* alloc() { 
    /* ... */ 
}

template<class T, class A0> 
T* alloc(const A0& a0) { 
    /* ... */ 
}

/* ... */

您可以使用preprocessor metaprogramming来处理重复,例如使用Boost.Preprocessor或简单地使用简单的脚本生成函数。

以下是使用Boost.PP的简单示例:

#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>

template<class T>
T* alloc() {
    return new T;
}

#define FUNCTION_ALLOC(z, N, _) \
  template<class T, BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), class T)> \
  T* alloc(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(N), const T, &p)) { \
     return new T( \
       BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), p) \
     ); \
  }

BOOST_PP_REPEAT(10, FUNCTION_ALLOC, ~)

#undef FUNCTION_ALLOC

这会为最多10个参数生成alloc()个模板函数。

答案 1 :(得分:0)

解决问题的前C ++ 11解决方案是只提供一个简单的alloc函数来构造其参数的副本。 20多年来,这就是C ++ 03分配器和所有容器的工作方式。将它应用于您的代码:

template <typename T>
inline T *alloc(const &T arg) {
    T *p;

    if (_free.empty()) {
        p = new T(arg);
    } else {
        p = _free.front();
        _free.pop();

        // to call the ctor of T, we need to first call its DTor
        p->~T();
        p = new( p ) T(arg);
    }
    return p;
}

然后你把它称为:

// copy construct T into the allocator's memory:
instance_of_your_allocator.alloc(T(1, 2, 3));

这种方法的缺点是它需要一个拷贝构造函数,并且它可能是一个代价高昂的操作。

又一个例子:

vector<T> vec;
vec.push_back(T(1, 2, 3)); // C++03 way, uses move cons-tor in C++11 if possible.
vec.emplace_back(1, 2, 3); // C++11 way, constructs in-place