2010-10-29 4 views
1

Я делаю то, что кажется, что его можно улучшить, но у меня нет достаточных навыков для его улучшения. Вы можете помочь?лучший способ сделать это?

Дан:

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

Я чувствую, как заявление переключателя плохо, потому что во время компиляции всех значений перечислений известны, так что теоретически мы уже знаем, какие типов должны пойти в векторе материал. Но мы делаем это во время выполнения.

Коротко писать генератор кода для этого, есть ли лучший способ?

+1

«во время компиляции все значения перечисления известны» - вы имеете в виду, что знаете содержимое «metaDataContainer»? Это не выглядит так. И 'switch' - это достойный способ реализации фабричного шаблона. – aschepler

+0

Вы правы, я не знаю, что содержит контейнеры, но я знаю все возможные значения, которые он может содержать. Поэтому, если MetaData - это перечисление с A, B, C. Я знаю, что это возможности, но я мог бы просто получить A и C. – anio

ответ

3

Не совсем. Однако вы можете абстрагировать большую часть шаблона с помощью factory type и использовать boost::ptr_vector или контейнер с интеллектуальными указателями для рационального использования ресурсов. (See comments о выборе между смарт-контейнером и немым контейнером смарт-указателей.)

3

Ну, вы можете предварительно выделить функцию отображения мета->, которая создает необходимый производный тип.

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]))()); 
} 

т.д.

Пожалуйста, не забудьте рассмотреть случай, когда значение мета нет в карте!

Для конкретного случая, если ваши значения метаданных являются малыми числами, вы можете даже устранить во время выполнения накладных расходов:

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

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

- но такой подход, возможно, слишком низкий уровень и подвержены ошибки. (Надежность такой инициализации допускается синтаксисом C++.)

0

Вы спрашиваете о Заводской шаблон. Для этого вы можете использовать Google. Чтобы максимально использовать во время компиляции (w.r.t. run-time), вы, вероятно, захотите добавить условия поиска , используя шаблоны.

Но, поскольку вы '' вектор метаданных '' содержит информацию во время выполнения, вам понадобится что-то динамическое. enum не такая уж плохая идея - посмотрите здесь, например: http://www.daniweb.com/forums/thread18399.html. Обратите внимание также на бит в конце с typedef InstantiatorMap::value_type InstantiatorMapEntryType. Используется отображение указателей '' enums '' на '' указатели функций-членов '' как фабрики.

+1

А, и, возможно, вам захочется обновить название вашего вопроса ... если возможно. – 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

Хорошее использование конструктора карты. – Vlad