Общий класс распределителя без шаблонов с переменным значением? - PullRequest
3 голосов
/ 08 апреля 2010

Я пытаюсь написать общий класс распределителя, который на самом деле не освобождает память объекта, когда он свободен () 'd, но держит его в очереди и возвращает ранее выделенный объект, если запрашивается новый. Теперь я не могу понять, как передавать аргументы конструктору объекта при использовании моего распределителя (по крайней мере, не прибегая к переменным шаблонам). Функция 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 ]

3 голосов
/ 08 апреля 2010

Когда вам нужно настроить таргетинг на компиляторы до C ++ 0x, вам нужно предоставить псевдо-вариационные шаблоны, т. Е. Вам нужно предоставить функцию шаблона для каждой необходимой арности:

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

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

/* ... */

Вы можете использовать метапрограммирование препроцессора , хотя для обработки повторений, например, используя 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

Это генерирует вам alloc() шаблонные функции для до 10 аргументов.

0 голосов
/ 10 марта 2012

Решение проблемы до C ++ 11 заключается в предоставлении только одной простой функции alloc, которая создает копию своего аргумента. Так C ++ 03 и все контейнеры работали более 20 лет. Применяя его к вашему коду, он становится:

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