Я хочу использовать статический член в классе шаблона для создания экземпляра объекта-одиночки для каждого класса, который наследуется от этого класса шаблона.
Вот пример:
#include <iostream>
#include <vector>
struct X{
static std::vector<X*>& getRegistry(){
static std::vector<X*> registry;
return registry;
}
X(){
getRegistry().push_back(this); // Each X adds itself to the registry
}
};
template<typename T>
struct Y : X{
private:
static T instance; // The per-type singleton
};
template<typename T>
T Y<T>::instance {};
Идея состоит в том, что объекты типа X
вводить себя в «реестр» всякий раз, когда они создаются. Учебный класс Y<T>
что происходит от X
является шаблоном класса, который должен создавать экземпляр статического одноэлементного объекта каждого типа, который наследуется от него (с использованием любопытно повторяющегося шаблона).
Идея состоит в том, что «реестр» будет содержать один объект каждого класса, который наследуется от Y<T>
, Этим классам не нужно ничего делать, чтобы их добавили в реестр; вместо этого, просто наследуя от Y<T>
должно быть достаточно для создания одноэлементного объекта, который добавляется в реестр.
Я попробовал свой код так:
struct A : Y<A>{};
struct B : Y<B>{};
struct C : Y<C>{};
int main(){
std::cout << "Number of objects in the registry: " << X::getRegistry().size() << std::endl;
// Should print "3"}
Скриптовая ссылка: http://ideone.com/aWDEg4
Желаемое поведение должно быть таким A
, один B
, и один C
, должен быть в реестре. Но ни один из них не является. Проблема в том, что Y<T>::instance
не создается ни для одного из классов, так как он не используется в коде. Тем не менее, я никогда не хочу использовать эти поля, они просто для создания экземпляра синглтона. Таким образом, существует ли способ вызвать создание экземпляра статического поля без необходимости добавления дополнительного кода к производным классам (т.е. A
,B
, а также C
)?
Я знаю, что могу явно создать экземпляр template class Y<A>;
, но это добавило бы дополнительный код к производному классу A
,
Вы можете просто создать статические экземпляры:
struct A : Y<A>{};
struct B : Y<B>{};
struct C : Y<C>{};
static A a;
static B b;
static C c;
int main(){
std::cout << "Number of objects in the registry: " << X::getRegistry().size() << std::endl;
}
выход:
Number of objects in the registry: 3
Я не думаю, что вы можете избежать привлечения клиентов Y
, но вы можете сделать Y
частный конструктор форсирование участие клиента. Например, это работает так, как вы хотите:
template<typename T>
struct Y : X {
Y(const Y<T> &other) {}
static Y<T> create() { &instance; return Y<T>(); }
private:
static T instance; // The per-type singleton
Y() {}
};
template<typename T>
T Y<T>::instance {};
struct A : Y<A> { A() : Y(Y::create()) {} };
struct B : Y<B> { B() : Y(Y::create()) {} };
struct C : Y<C> { C() : Y(Y::create()) {} };
Участие клиента является вызовом Y::create
что также случается, чтобы заставить экземпляр instance
член. Конечно, это, вероятно, не то, что вы хотели, но это работает. Обратите внимание, мой предыдущий комментарий о this
Указатель будет по-прежнему применяться, даже если вы можете добавить статические экземпляры в свой реестр.