我正在使用GLFW进行C++应用程序中的窗口和输入管理。为了使用成员函数作为关键事件的回调函数,我按照答案here中的建议使用了单例。替代模板参数的转换构造函数
但是,我需要实现不同的输入处理程序。我的方法是使用Singleton作为实际输入处理程序(controller_)的包装以允许多态。但是,为了实例化Singleton,基类不能是抽象的。该解决方案涉及使用CRTP以便能够从基类的实现中调用特定的输入处理方法。
template <class T>
class Controller : public BC{ //BC is just for using this class as a template parameter itself
public:
Controller(){}
Controller(Controller &controller){
controller_ = &controller;
}
static Controller& getInstance(Controller *controller){
static Controller instance(*controller);
return instance;
}
//This is the key move, where the concrete implementation is invoked.
static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){
Controller *aux;
(static_cast<T>(getInstance(aux))).keyCallbackImpl(window, key, scancode, action, mods);
}
//Stub to be overridden by the concrete input handler
virtual void keyCallbackImpl(GLFWwindow* window, int key, int scancode, int action, int mods){}
//This is the wrapped input handler
Controller *controller_;
};
这工作正常。但是,派生类存在问题。为了能够执行转换,我必须定义一个转换构造函数。
SMController(Controller<SMController> &c){
controller_ = c.controller_;
std::cout << "Constructor" << std::endl;
}
这是不方便的,原因有二:
- 用户从控制器导出必须明确定义这个构造
- 新包装的每一个键被按下时的建筑似乎昂贵
使用这种设计有没有替代这种转换?
编辑: 我结束了与T.C.的提案,但略有不同。由于我需要具有自己的一组参数的子类,因此能够在构造函数中提供它们是理想的。初始化单例的单独调用很容易出错,因为它可以用错误的模板参数完成,或者只是被遗忘。
为了使与它的参数,并且在一个呼叫其对应的单专门对象的实例化,我不停使用CRTP和我加入此构造基类:现在
Controller<T>(){
T::getInstance((T*)this);
}
,与只需一个电话我就可以得到我需要的一切:
std::shared_ptr<BaseController> c(new SMController(params_, window_));
对不起,如果aux未初始化,getInstance(aux)应该如何工作?我错过了什么吗? – 2014-08-29 19:45:08
单例是静态的,所以它仅在第一次调用'getInstance()'时被实例化(这是在别处完成的)。 – broncoAbierto 2014-08-29 19:49:36
典型的CRTP实现从'Base *'到'T *'或'* this'从'Base &'到'T&'投射'this'。 –
2014-08-29 20:01:43