对于我正在编写的应用程序,一个重要的部分是用户可以为不同的进程选择任何可用选项。所有这些选项都派生自相同的基类。我偶尔会添加新的选项,我想让这个过程尽可能简单。因此,在浏览网络和SO之后,我就是这样:
基类:
class Base {
double some_member;
virtual double some_method() = 0;
};
派生类:
class Derived : Base {
//...
};
用于保存可用类型表并根据指定名称创建派生类的工厂:
template <typename B>
class Factory{
public:
template <typename D>
void registerType(std::string name)
{
static_assert(std::is_base_of<B, D>::value, "class doesn't derive from the base");
table_[name] = &createFunc<D>;
}
B* create(std::string name)
{
const auto it = table_.find(name);
if(it != table_.end())
return it->second();
FILE_LOG(logERROR) << "unidentified option, acceptable options are:";
for(auto const &m : list())
FILE_LOG(logERROR) << '\t' << m;
return nullptr;
}
std::vector<std::string> list()
{
std::vector<std::string> lst;
for(auto const &iter : table_)
lst.push_back(iter.first);
return lst;
}
private:
template<typename D>
static B* createFunc()
{
return new D();
}
typedef B* (*PCreateFunc)();
std::map<std::string, PCreateFunc> table_;
};
包含特定流程的所有选项的类:
class OptsContainer {
private:
std::vector<std::unique_ptr<Base>> opts_;
public:
//some other stuff
void addOption(const std::string &); //adds a new option with given name
static Factory<Base> factory;
};
Factory<Base> OptsContainer::factory;
void OptsContainer::addOption(const std::string &name)
{
opts_.push_back(std::unique_ptr<Base>(factory.create(name)));
}
此时,每当我添加一个新的派生类时,我只需要在工厂表中注册该类:
///All older includes
#include "derived42.h"
void initOptions()
{
//all other registrations
OptsContainer::factory.registerType<Derived42>("Derived42");
}
我在节目开始时拨打initOptions
。这很有效,但我觉得应该可以做得更好。我想要的是只需添加#include "derived42"
和类型来注册自己,因此不需要initOptions
函数并在一开始就调用它。
我是否必须使用Boost / Loki / ...(如另一篇文章中所述)?这甚至可以在vanilla c ++中使用吗?或者我现在应该和我拥有的一样生活?仅供参考,我使用Visual Studio Express 2015编写程序,但我也可以将代码移到Linux(gcc)。换句话说,不喜欢使用VS2015中未实现的c ++ 11 / c ++ 14模式,但如果需要,我可以轻松地将所有内容移动到gcc。
答案 0 :(得分:1)
你的代码对我来说太复杂了。也许我错过了一个原因。
你无法避免注册。您正在寻找的是在编译时注册,我认为这是不可能的。由于您在编译时寻找注册,这意味着您不需要在接口中公开注册方法。因此,您的客户端接口应该由基类和创建方法组成:
// { client interface header
class B
{
public:
virtual ~B() = 0 {}
//...
};
B* Create( const char* s );
// } client interface header
一个简单的创建功能:
// { client interface implementation
template< typename T >
B* New()
{
return new T;
}
typedef B* (*PFNew)();
B* Create( const char* s )
{
typedef std::map< string, PFNew > Map;
static Map m;
if ( ! m.size() )
{
m[ D1::Signature() ] = New< D1 >;
m[ D2::Signature() ] = New< D2 >;
//...
}
Map::const_iterator ci = m.find( s );
if ( ci == m.end() )
throw -1;
return ci->second();
}
// } client interface implementation