使用静态初始化来注册类

时间:2014-12-27 23:54:54

标签: c++ c++11

所以我读了这篇关于使用静态初始化来注册类(http://quantumgraphics.blogspot.nl/2014/11/abusing-static-initialization.html)的文章。这正是我所需要的,所以我决定实施它。然而,我无法让它工作,所以我做了一个小测试案例,以确保我得到了正确的细节。事实证明,即使是一个简单的例子也不起作用(http://ideone.com/HDr8ZM):

#include <iostream>

int a = 0;

template<
    class T
>
class Scriptable {
protected:
    struct Proxy
    {
        Proxy() {
            std::cout << "Proxy was executed! ID: " << T::id << std::endl;
            a++;
        }
    };
    static Proxy proxy_;
} ;

template<
    class T
>
typename Scriptable<T>::Proxy Scriptable<T>::proxy_;

class Object : public Scriptable<Object> {
public:
    constexpr static auto id = "[Object]";
} ;

int main() {
    std::cout << "Done " << a << std::endl;
}

所以基本上需要发生的事情(或者更确切地说,我想要发生的事情)是代理构造函数应该在main之前执行。我想使用Proxy构造函数向一些单例基类工厂注册该类,但我不认为与此代码相关的代码无效。

有人能指出我正确的方向吗?我可能错过了编译器标志或其他东西(该示例应仅使用-std = c ++ 11标志进行编译)。或者是否有更好的方法来做我在这里尝试的事情?

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

通过Pradhan的链接,我能够做出我需要的东西:

#include <iostream>

int a = 0;

template <typename T, T /*unnamed*/>
struct nnb_ForceInit { };

template<
    class T
>
class Scriptable {
public:
    struct nnb_Proxy {
        nnb_Proxy() {
            std::cout << "Proxy was executed! ID: " << T::id << std::endl;
            a++;
        }
    };

    static nnb_Proxy __nnb_proxy__;
    typedef nnb_ForceInit<nnb_Proxy&, __nnb_proxy__> __nnb_typedef_dummy__;
} ;

template<
    class T
>
typename Scriptable<T>::nnb_Proxy Scriptable<T>::__nnb_proxy__;

class Object : public Scriptable<Object> {
public:
    constexpr static auto id = "[Object]";
};

class Image : public Scriptable<Image> {
public:
    constexpr static auto id = "[Image]";
};

class Error : public Scriptable<Error> {
public:
    constexpr static auto id = "[Error]";
} ;

int main() {
    std::cout << "Done " << a << std::endl;
}

我不清楚它是如何正常工作的,但似乎做了我想要/工作得很好的事情,所以我想这就是它。

答案 1 :(得分:1)

它没有用,因为你的Proxy没有理由构建。在这种情况下,您的main()甚至无法构建Object - 那么为什么Proxy会被构建?你必须至少这样做:

int main() {
    Object o;
    std::cout << "Done " << a << std::endl;
}

但是,简单地构建o并不以任何方式引用代理,因此仍然没有理由构造代理。你不得不以某种方式触摸它。最简单的方法是在Scriptable的构造函数中引用它:

Scriptable() {
    proxy_; // this line throws a warning, since this line does nothing,
            // so replace it with something reasonable. but this line is
            // enough to force proxy_ to be instantiated.
}

如果我添加这两位(Object o;Scriptable构造函数),那么您的代码会产生:

Proxy was executed! ID: [Object]
Done 1

另一种方法是在构造函数中实际声明proxy_

Scriptable() {
    static Proxy proxy_;
}