Автоматически строить карту из строк в шаблонную фабричную функцию

Я хотел бы иметь возможность создавать набор шаблонный Объекты C ++ на основе выбранных параметров командной строки. Решение ниже (предложено Есть ли способ создания объектов из строки, содержащей их имя класса? ) сработает, если будут созданы экземпляры типов (т.е. Character классы) не были шаблонными.

Также важно: код ниже позволяет каждому подклассу Character зарегистрировать себя. Это означает, что пользователи могут добавлять дополнительные подклассы Character без необходимости касаться какого-либо кода в библиотеке или явно управлять списком всех возможных подтипов. Вопрос: Есть ли способ получить такую ​​же функциональность для шаблонных классов?

Пользователи библиотеки выбирают значение параметра шаблона при разборе командной строки в main, Это означает, что CharacterDescription::make и, как следствие, CharacterDescription класс также должен быть шаблонным. На данный момент, я не могу понять, как позволить каждому Character подкласс «регистрируется» сам, не поддерживая центральный список всех возможных подклассов. Шаблонная версия makeCharacters ниже почти делает то, что я хочу — я просто хочу настроить код так, чтобы makeCharacters не поддерживает список всех подклассов.

(Я подозреваю, что для ответа потребуется некоторая магия #define; но я не вижу, как это сделать.)


Character.hpp

// Base Class
class Character {

};

// Descriptor for subclasses that may be instantiated.
// (i.e., contains the parameters used for the option parser
// as well as a pointer to a factory function)
class CharacterDescription {

typedef Character* (*CharacterFactory)(const char* params);

public:
const char* optionName;
const CharacterFactory factory;

CharacterDescription(const char* pOpt, const CharacterFactory pFactory) :
optionName(pOpt), factory(pFactory) {
characterList.push_back(*this);
}

template<typename T>
static Character *make(const char *params) {
return new T(params);
}

static vector<CharacterDescription> characterList;

};

Character.cpp

vector<CharacterDescription>  CharacterDescription::characterList;

Animal.hpp

// Example subclass that may be requested on the command line.
class Animal : public Character {

public:
Animal(const char* /*params*/) {}

public:
static CharacterDescription description;
};

Animal.cpp

CharacterDescription Animal::description("animal", CharacterDescription::make<Animal>);

main.cpp

    // Yes, this is gross, but it gets the point across
vector<Character*> makeCharacters(int argc, const char* argv[]){

vector<Character*> characters;
for (int i = 1;i < argc; i++) {
const char* current = argv[i];
auto foundItem = std::find_if(CharacterDescription::characterList.begin(),
CharacterDescription::characterList.end(),
[current](const CharacterDescription& item) {return strcmp(item.optionName,current)==0;});
if (foundItem != CharacterDescription::characterList.end() ) {
characters.push_back((*foundItem).factory(argv[i+1]));
}
}
return characters;
}

шаблонная версия makeCharacters

template<typename T>
vector<Character<T>*> makeCharacters(int argc, const char* argv[]){

vector<CharacterDescription<T>> characterList;

//
// **Key question:**  Is there a way to distribute these lines of code
// to the .hpp or .cpp file for each subclass?
//
characterList.push_back({"animal", CharacterDescription<T>::template make<Animal<T>>});
characterList.push_back({"tree", CharacterDescription<T>::template make<Tree<T>>});
characterList.push_back({"rock", CharacterDescription<T>::template make<Rock<T>>});

vector<Character<T>*> characters;
for (int i = 1;i < argc; i++) {
const char* current = argv[i];
auto foundItem = std::find_if(characterList.begin(),
characterList.end(),
[current](const CharacterDescription<T>& item) {return strcmp
(item.optionName,current)==0;});
if (foundItem != characterList.end() ) {
characters.push_back((*foundItem).factory(argv[i+1]));
}
}
return characters;
}

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …