2014-11-15 119 views
0

最后类调用静态方法如何能够做到用C++ 11以下设计:设计模式,在

class Consumer : Base<Consumer> 
{ 
    // different consumers will have different methods (of the same signature) 
    void Foo(){...} 
    void Bar(){...} 
    : // etc. 

    static void override 
    register_all() { 
     register_method<&Consumer::Foo>("foo"); 
     register_method<&Consumer::Bar>("bar"); 
     : // etc. 
    } 
    : 
} 

template<typename T> 
class Base 
{ 
    static 
    Base() { 
     register(); 
    } 

    virtual static void 
    register_all(){ }; 

    using F = void(T::*)(); 

    template<F f> 
    static void 
    register_method(std::string name) { 
     ... 
    } 
} 

...?

请注意,我做了两件违法的事情:

  • 我使用静态构造函数(不允许)在基类
  • 我使用虚拟静态函数(也不允许)

注意:在访问第一个实例(它将填充一个静态C函数指针表)之前,方法的注册只需要进行一次。

最后,有没有更好的技术可以使用,某种方式需要注册的标记或标记方法,并保存消费者在手动注册到单独函数中的麻烦?

+1

'register'是C++中的关键字。 –

+1

我不明白你在这里做什么。在工作中有太多虚构的结构使得难以遵循整体观点。 – Rapptz

+0

您想要注册的方法的名称是已知的还是全局固定的,还是每个派生类都决定要注册什么? –

回答

2

我相信经常的CRTP可以正常工作。这摆脱了virtualstatic。使用std::once_flag结合std::call_once将允许您只调用一次函数 - 模仿“静态构造函数”的效果。它只是需要一点点搞乱。

全码:

#include <iostream> 
#include <mutex> 

template<typename T> 
struct Base { 
    Base() { 
     static_cast<T*>(this)->register_all(); 
    } 

    using F = void(T::*)(); 

    template<F f> 
    void register_method(const char* str) { 
     // ... 
     std::cout << "registered " << str << '\n'; 
    } 
}; 

struct Derived : Base<Derived> { 
private: 
    static std::once_flag flag_; 
    void implementation() { 
     register_method<&Derived::foo>("foo"); 
     register_method<&Derived::bar>("bar"); 
    } 
public: 
    void foo() {} 
    void bar() {} 

    void register_all() { 
     std::call_once(flag_, [this]{ implementation(); }); 
    } 
}; 

std::once_flag Derived::flag_; 

int main() { 
    Derived x; 
    Derived y; 
} 

Live Demo

+0

这并没有解决“一次性注册”的问题 - 我在问题中写下了一个注释,使其更加清晰。 –

+0

@Pi你可能会用['std :: call_once'](http://en.cppreference.com/w/cpp/thread/call_once)做一些诡计,因为提出的语法是不可能的(可以' t拥有依赖于非静态成员函数的静态成员函数)。 – Rapptz

+0

对不起,我对初始伪代码做了很多错误:/我已经添加了必要的static-s。顺便说一句,CRTP很好地解决了静态覆盖问题 - 谢谢! –

0

我修改Rapptz的回答把所有的机器放回底座类:

http://coliru.stacked-crooked.com/a/52fd723e905333c6

#include <iostream> 
#include <mutex> 

template<typename T> 
struct Base { 
    Base() { 
     std::call_once(flag_, T::register_all); 
    } 

    using F = void(T::*)(); 

    template<F f> 
    static void register_method(const char* str) { 
     // ... 
     std::cout << "registered " << str << '\n'; 
    } 
public: 
    static std::once_flag flag_; 
}; 

// have to initialise static-s outside class... 
template<typename T> 
std::once_flag Base<T>::flag_{}; 

.. 。

struct Derived1 : Base<Derived1> { 
public: 
    static void register_all() { 
     std::cout << "D1" << '\n'; 
     register_method<&Derived1::foo>("foo"); 
     register_method<&Derived1::bar>("bar"); 
    } 
public: 
    void foo() {} 
    void bar() {} 
}; 

struct Derived2 : Base<Derived2> { 
public: 
    static void register_all() { 
     std::cout << "D2" << '\n'; 
     register_method<&Derived2::woot>("woot"); 
    } 
public: 
    void woot() {} 
}; 

...

int main() { 
    Derived1 x; 
    Derived1 y; 

    Derived2 z; 
} 

编辑:奇怪的是我需要初始化自己的旗帜与{}但Rapptz没有。为什么是这样?

EDIT2:此代码在ideone上失败,因为ideone不使用-pthread编译器标志。使用更简单的'static bool first = true;如果(第一个){first = false; ...}构造会执行这个技巧,因为C++ 11规定静态变量的初始化是线程安全的。

+1

“*编辑:奇怪的是我需要用{}初始化我的国旗,但是Rapptz没有。为什么会这样?*”因为GCC的bug。 – ildjarn