自动构建从字符串到模板化工厂函数的映射 我希望能够基于选定的命令行参数实例化一组模板化C++对象。如果要实例化的类型(即字符类)没有模板化,下面的解决方案(建议的)将起作用
同样重要的是:下面的代码允许自动构建从字符串到模板化工厂函数的映射 我希望能够基于选定的命令行参数实例化一组模板化C++对象。如果要实例化的类型(即字符类)没有模板化,下面的解决方案(建议的)将起作用,c++,templates,factory,instantiation,command-line-arguments,C++,Templates,Factory,Instantiation,Command Line Arguments,同样重要的是:下面的代码允许字符的每个子类注册自身。这意味着用户可以添加Character的其他子类,而无需触摸库中的任何代码或显式管理所有可能的子类型列表问题:有没有办法为模板化类获得相同的功能 库的用户在分析main中的命令行时选择模板参数的值。这意味着CharacterDescription::make,因此,CharacterDescription类也必须模板化。在这一点上,我不知道如何让每个字符子类在不维护所有可能子类的中心列表的情况下“注册”自己。下面的makeCharacters模
字符的每个子类注册自身。这意味着用户可以添加Character
的其他子类,而无需触摸库中的任何代码或显式管理所有可能的子类型列表问题:有没有办法为模板化类获得相同的功能
库的用户在分析main
中的命令行时选择模板参数的值。这意味着CharacterDescription::make
,因此,CharacterDescription
类也必须模板化。在这一点上,我不知道如何让每个字符子类在不维护所有可能子类的中心列表的情况下“注册”自己。下面的makeCharacters
模板版本几乎满足了我的要求——我只想设置代码,这样makeCharacters
就不会维护所有子类的列表
(我怀疑答案需要一些“定义魔法”;但是,我不知道怎么做。)
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;
};
动物蛋白
CharacterDescription Animal::description("animal", CharacterDescription::make<Animal>);
在所有派生类中都已经有了静态的CharacterDescription
,不是吗?每个构造函数都将自己注册到CharacterDescription::characterList
。是的,但这是针对非模板版本的。当您将Character和CharacterDescription类设置为模板时,无法将CharacterDescription添加到派生类中,因为您不知道t是什么。您在所有派生类中都已经有一个静态的CharacterDescription
,不是吗?每个构造函数都将自己注册到CharacterDescription::characterList
。是的,但这是针对非模板版本的。将Character和CharacterDescription类设置为模板时,无法将CharacterDescription添加到派生类中,因为您不知道t是什么。
// Example subclass that may be requested on the command line.
class Animal : public Character {
public:
Animal(const char* /*params*/) {}
public:
static CharacterDescription description;
};
CharacterDescription Animal::description("animal", CharacterDescription::make<Animal>);
// 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;
}
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;
}