2010-04-08 4 views
3

J'essaye d'écrire une classe allocator générique qui ne libère pas réellement la mémoire d'un objet quand elle est libre() mais la garde dans une file d'attente et retourne un objet précédemment assigné si un nouveau est demandé. Maintenant, ce que je ne peux pas comprendre est de savoir comment passer des arguments au constructeur de l'objet lorsque j'utilise mon allocateur (du moins sans avoir recours à des modèles variés, c'est-à-dire). La fonction alloc() je suis venu avec se présente comme suit:Classe d'allocateur générique sans modèles variadiques?

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; 
} 

encore, je dois le code pour être compatible avec (et les anciennes versions de GCC qui ne prennent pas en charge les modèles variadique) d'aujourd'hui C++. Existe-t-il un autre moyen de transmettre une quantité arbitraire d'arguments au constructeur d'objets?

Répondre

3

Lorsque vous avez besoin de cibler les compilateurs pré-C++ 0x vous avez besoin pour fournir des modèles pseudo-variadique, à savoir que vous devez fournir une fonction de modèle pour tous les besoins arité:

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

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

/* ... */ 

Vous pouvez utiliser preprocessor metaprogramming bien pour gérer les répétitions, par exemple en utilisant Boost.Preprocessor ou en générant simplement les fonctions en utilisant un script simple.

Voici un exemple simple en utilisant 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 

Cela vous génère alloc() fonctions de modèle jusqu'à 10 arguments.

+0

peut stimuler aider? – UncleBens

+0

Oui, Boost.PP aide - je pense que @GMan a eu un bel exemple quelque part, va essayer de le déterrer. –

+0

Je fais beaucoup de choses sur le préprocesseur Boost, mais je ne pense pas avoir mis beaucoup sur le site. Matthieu en a fait un récemment, cependant: http://stackoverflow.com/questions/2597586/simplifying-templates/2598283#2598283 – GManNickG

0

La solution pré-C++ 11 au problème consiste à fournir une seule fonction simple alloc qui construit une copie de son argument. C'est ainsi que fonctionnaient les allocateurs C++ 03 et tous les conteneurs, depuis plus de 20 ans. Son application à votre code devient:

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; 
} 

Et puis vous l'appelez comme:

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

L'inconvénient de cette approche est qu'elle nécessite une copie-constructeur soit disponible, et son potentiellement opération coûteuse.

Un autre exemple:

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 
Questions connexes