我正在尝试自动注册CRTP工厂类。 我的目标是不使用宏来注册类类型,并且不显式调用注册方法。
我根据this answer进行了尝试:
factory.h
template<typename Base>
struct Factory{
static Base* create(const QString& name){
auto callable = map.value(name);
return callable();
}
template<typename Derived>
static void subscribe(QString name){
// insert already-exist-check here
qDebug() << "registered: " << name;
map.insert(std::move(name), [](){return new Derived{};});
}
static QMap< QString, std::function<Base*(void)> > map;
};
template<typename Base>
QMap< QString, std::function<Base*(void)> > Factory<Base>::map;
template<typename Base, typename Derived>
class Registrable{
protected:
virtual QString registerName() const = 0;
Registrable(){
isRegistered;
}
~Registrable() = default;
static bool init(){
Derived t;
Factory<Base>::template subscribe<Derived>(t.registerName());
return true;
}
private:
static bool isRegistered;
};
template<typename Base, typename Derived>
bool Registrable<Base, Derived>::isRegistered = Registrable<Base, Derived>::init();
main.cpp
struct MyFactoryBase{
virtual ~MyFactoryBase() = default;
virtual void method() const = 0;
};
struct MyFactory1 : public MyFactoryBase, public Registrable<MyFactoryBase, MyFactory1>{
QString registerName() const override{
return "Class1";
}
void method() const override{ qDebug() << "yay Class1"; }
MyFactory1() : MyFactoryBase(), Registrable<MyFactoryBase, MyFactory1>(){}
};
struct MyFactory2 : public MyFactoryBase, public Registrable<MyFactoryBase, MyFactory2>{
QString registerName() const override{
return "Class2";
}
void method() const override{ qDebug() << "yay Class2"; }
MyFactory2() : MyFactoryBase(), Registrable<MyFactoryBase, MyFactory2>(){}
};
int main(){
// auto* fac = Factory<MyFactoryBase>::create("Class1");
// auto* fac2 = Factory<MyFactoryBase>::create("Class2");
}
在第一次订阅期间尝试使用map.insert()时,它崩溃并出现段错误。我想念的是什么?
答案 0 :(得分:2)
如评论中所建议,它是static initialization order fiasco。
我按照ISOCpp的建议解决了它 How do I prevent the “static initialization order problem” for my static data members?
无论如何,将X :: x_静态数据成员更改为静态成员函数始终是可移植且安全的:
正在更改
static QMap< QString, std::function<Base*(void)> > map;
到
static QMap< QString, std::function<Base*()> >& map(){
static QMap< QString, std::function<Base*()> > map;
return map;
}
并用map
更新来自map()
的所有呼叫,即可解决此问题。
int main(){
auto* fac = Factory<MyFactoryBase>::create("Class1");
auto* fac2 = Factory<MyFactoryBase>::create("Class2");
fac->method();
fac2->method();
return 0;
}
输出:
registered: Class1
registered: Class2
yay Class1
yay Class2