2010-04-08 7 views
3

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

ответ

3

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

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 

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

+0

может повысить помощь с этим? – UncleBens

+0

Yep, Boost.PP помогает - я думаю, что у @GMan был хороший пример где-нибудь, попытается его выкопать. –

+0

Я делаю много материала для подготовки препроцессора, но я не думаю, что много положил на сайт. Matthieu сделал недавно, хотя: http://stackoverflow.com/questions/2597586/simplifying-templates/2598283#2598283 – GManNickG

0

Решение проблемы, предшествующее 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 
Смежные вопросы