2014-11-18 2 views
0

Я хочу использовать статический член в классе шаблона для создания экземпляра одноэлементного объекта для каждого класса, который наследует этот класс шаблонов.Формирование экземпляра статических элементов в классе шаблона

Вот пример:

#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.

+0

Бьюсь об заклад, ваша проблема связана с использованием указателя 'this' из конструктора' X'. Внутри конструктора указатель 'this' не гарантированно указывает на завершенный производный объект. – b4hand

+5

вы никогда не создаете экземпляры ваших структур, как еще будет работать конструктор? – AlexanderBrevig

+0

x vs y проблема, может быть? – IdeaHat

ответ

1

Вы можете просто создать статические экземпляры:

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 
+0

Да, но это заставляет меня добавлять дополнительный код для каждого производного класса, который я пытался избежать с помощью 'Y '. С вашим подходом я мог бы полностью отбросить класс 'Y '. – gexicide

0

Я не думаю, что вы можете избежать привлечения клиентов из Y, но вы можете сделать конструктор Y «S частная форсирование участие клиентов. Например, это работает, как вы хотите:

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 по-прежнему будет применяться, даже если вы можете добавить статические экземпляры в реестр.