2010-10-29 3 views
1

Je fais quelque chose qui semble pouvoir être amélioré, mais je n'ai pas assez de compétences pour l'améliorer. Pouvez-vous aider?meilleur moyen de le faire?

Étant donné:

vector<Base*> stuff; 
const vector<MetaData>& metaDataContainer = Config.getMetaData(); 

for(vector<MetaData>::const_iterator i = metaDataContainer.begin(), end = metaDataContainer.end(); i != end; ++i) 
{ 
    Base* pCurrent = buildDerivedType(*i); 
    stuff.push_back(pCurrent); 
} 

Base* buildDerivedType(MetaData meta) 
{ 
    Base* pRetval = NULL; 

    switch(meta) 
    { 
    case MetaData::A: 
    pRetval = new Alpha(); 
    break; 

    case MetaData::B: 
    pRetval = new Beta(); 
    break; 

    //so on so forth 
    }; 
    return pRetval; 
} 

je me sens comme l'instruction switch est mauvais car au moment de la compilation de toutes les valeurs de ENUM sont connues, donc théoriquement nous savons déjà quels types ont besoin d'aller dans des trucs de vecteur. Mais nous le faisons à l'exécution.

À court d'écrire un générateur de code pour cela, existe-t-il un meilleur moyen?

+1

"Lors de la compilation, toutes les valeurs enum sont connues" - vous voulez dire que vous connaissez le contenu de 'metaDataContainer'? Ça ne ressemble pas à ça. Et 'switch' est une façon décente de mettre en œuvre un modèle d'usine. – aschepler

+0

Vous avez raison, je ne sais pas ce que les conteneurs contiennent, mais je connais toutes les valeurs possibles qu'il pourrait contenir. Donc, si MetaData est enum avec A, B, C. Je sais que ce sont les possibilités, mais, je pourrais juste obtenir A et C. – anio

Répondre

3

Pas vraiment. Cependant, vous pouvez faire abstraction d'une grande partie du passe-partout avec un factory type et utiliser boost::ptr_vector ou un conteneur de pointeurs intelligents pour gérer les ressources de façon intelligente. (See comments sur le choix entre un conteneur intelligent et un conteneur binaire de pointeurs intelligents.)

3

Eh bien, vous pouvez préallouer une méta-fonction de mappage qui crée le type dérivé nécessaire.

typedef Base* ((*DerivedTypeCreator)()); 
map <MetaData, DerivedTypeCreator> derivedTypeBuilders; 

// ... 
derivedTypeBuilders[MetaData::A] = &CreateAlpha; 
derivedTypeBuilders[MetaData::B] = &CreateBeta; 

Base* CreateAlpha() 
{ 
    return new Alpha(); 
} 

Base* CreateBeta() 
{ 
    return new Beta(); 
} 

// ... 
for(vector<MetaData>::const_iterator i = metaDataContainer.begin(), 
     end = metaDataContainer.end(); 
    i != end; ++i) 
{ 
    stuff.push_back((*(derivedTypeBuilders[*i]))()); 
} 

etc.

S'il vous plaît ne pas oublier de considérer le cas lorsque la valeur de méta n'est pas sur la carte!

Pour le cas particulier si vos valeurs de métadonnées sont de petits nombres, vous pouvez même éliminer les frais généraux d'exécution:

DerivedTypeCreator[] derivedTypeBuilders = { 
    &CreateAlpha, // Metadata::A == 0 
    &CreateBeta // Metadata::B == 1 
}; 

// ... 
stuff.push_back((*(derivedTypeBuilders[(int)*i]))()); 

- mais cette approche est peut-être trop faible niveau et sujette aux erreurs. (Espérons qu'une telle initialisation est autorisée par la syntaxe C++.)

0

Vous vous posez des questions sur le Factory Pattern. Vous pouvez google pour cela. Pour mettre autant que possible dans la compilation (w.r.t. run-time), vous voulez probablement ajouter les termes de recherche en utilisant les modèles. Mais, puisque vous «vecteur de métadonnées» contient les informations à l'exécution, vous aurez besoin de quelque chose de dynamique. Le enum n'est pas si mauvaise idée - regardez ici, par exemple: http://www.daniweb.com/forums/thread18399.html. Notez également le bit à la fin avec typedef InstantiatorMap::value_type InstantiatorMapEntryType. Un mappage de '' enums '' à '' membres de la fonction membres '' en tant qu'usines est utilisé.

+1

Ah, et vous voudrez peut-être mettre à jour le titre de votre question ... si possible. – towi

2
template<class T> Base* Creator() { return new T; } 
typedef Base* (*CreateType)(); 
typedef std::pair<const MetaData, CreateType> cpair; 

cpair mapper [] = 
{ 
    cpair(MetaA, Creator<A>), 
    cpair(MetaB, Creator<B>), 
}; 

std::map<MetaData, CreateType> typemap(&mapper[0], &mapper[sizeof(mapper)]); 

void foo(MetaData m) 
{ 
    Base* a = typemap[m](); 
} 
+0

Bon usage du constructeur de carte. – Vlad

Questions connexes