Поэтому я прочитал эту статью об использовании статической инициализации для регистрации классов (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;
}
Поэтому в основном то, что должно произойти (точнее, то, что я хочу сказать), заключается в том, что конструктор Proxy должен быть выполнен до main. Я хочу использовать конструктор Proxy для регистрации класса с некоторой базой базового класса singleton, но я не думаю, что связанный с этим код не работает.
Может ли кто-нибудь указать мне в правильном направлении? Мне, вероятно, не хватает флага компилятора или что-то (пример должен компилироваться только с флагом -std = С++ 11). Или, может быть, лучший способ сделать то, что я здесь пытаюсь?
Любая помощь очень ценится!
С ссылкой 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;
}
У меня нет четкого представления о том, как это работает, но похоже, что я делаю то, что хочу/отлично работает, поэтому я предполагаю, что это так.
Это не работает, потому что у вас нет причин для создания 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_;
}