我希望能够根据选定的命令行参数实例化一组模板化 C ++对象。如果要实例化的类型(即Character
类)没有模板化,下面的解决方案(由Is there a way to instantiate objects from a string holding their class name? 建议)将起作用。
同样重要的是:下面的代码允许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;
}