определение статического члена с базовым классом шаблона

Есть базовый класс:

template<class T_CLASS>
class TBase
{
  protected:
    static CSomeClass m_objSomeClass;

  public:
    inline void Set(CSomeClass f_objSomeClass) { m_objSomeClass = f_objSomeClass; }
};

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

class CSub1 : public TBase<CSub1>
{
   //...
};

class CSub2 : public TBase<CSub2>
{
  //...
};

Как выглядит это определение? Это вообще возможно? Я пробовал некоторые... но ничего не получалось:

template<class T_CLASS>
CSomeClass TBase<T_CLASS>::m_objSomeClass;

//In fact the next one worked in Visual Studio; 
// but not in with the armcc where I need it.
CSomeClass TBase<CSub1>::m_objSomeClass;
CSomeClass TBase<CSub2>::m_objSomeClass;

Какие-либо предложения? Спасибо, Мирко


person Mirco    schedule 27.07.2011    source источник
comment
Первый подход должен был сработать: template <typename T> CSomeClass TBase<T>::m_objSomeClass;, поэтому должно быть что-то, что вы не показываете в коде. Зависит ли CSomeClass от аргумента типа?   -  person David Rodríguez - dribeas    schedule 27.07.2011
comment
Я переместил определение в другой исходный файл, и, наконец, оно правильно компилируется и линкуется... Тем не менее я не знаю, что было не так раньше. CSomeClassis в A.hpp, базовые и подклассы находятся в B.hpp, который включает в себя A.hpp, а определение было в B.cpp. В любом случае... спасибо за помощь!   -  person Mirco    schedule 28.07.2011
comment
Определение должно быть доступно где используется поле. Это шаблонное определение, если вы укажете его в файле cpp, компилятор не будет создавать экземпляр статического члена.   -  person David Rodríguez - dribeas    schedule 28.07.2011
comment
@ Дэвид Родригес, не могли бы вы объяснить это подробнее? Теперь определение находится в D.cpp, поэтому оно предоставляется в файле cpp, и все работает нормально. В случае, если он есть, я не вижу разницы между шаблонным определением статического члена и нешаблонным.   -  person Mirco    schedule 28.07.2011
comment
Это длинное объяснение, но все сводится к тому, что если вы не предоставите определение в заголовке, а другой cpp создаст экземпляр вашего шаблона с новым типом, то компилятор не будет создавать экземпляр этого статического члена для вас (у него есть нет определения для создания экземпляра). Это точно та же причина, по которой вы должны предоставлять определения функций для шаблонов в заголовках, и этого можно избежать точно такими же способами (предоставьте их в cpp и принудительно создайте там экземпляры для всех необходимых вам типов), но это устраняет универсальность : новый код не может использовать другие аргументы.   -  person David Rodríguez - dribeas    schedule 28.07.2011
comment
@David, большое спасибо за объяснение. Наличие определения в заголовке работает и решает мою проблему.   -  person Mirco    schedule 28.07.2011


Ответы (3)


template<>
CSomeClass TBase<CSub1>::m_objSomeClass;
template<>
CSomeClass TBase<CSub2>::m_objSomeClass;

является одним из правильных способов, если вы хотите явно определить член static для сплошного класса, такого как CSub1, CSub2. Демо.

Изменить. Обычный способ — определить как:

template<class T_CLASS>
CSomeClass TBase<T_CLASS>::m_objSomeClass;

Оба способа послужат цели.

person iammilind    schedule 27.07.2011
comment
Это отлично работает в Visual Studio, но с компилятором armcc я снова получаю ошибки компоновщика (неопределенный символ). Я не знал ideone.com, спасибо за это :) - person Mirco; 27.07.2011
comment
@Mirco, это должно работать нормально. Вы проверили, правильно ли вы компилируете/связываете файл, где бы вы ни определяли static членов? (кстати, ideone — это просто онлайн-компилятор для запуска небольших фрагментов). - person iammilind; 27.07.2011
comment
Он должен быть скомпилирован и слинкован правильно... Есть ли способ неявно определить статические члены? Что-то не так с этим: template<class T_CLASS> CSomeClass TBase<T_CLASS>::m_objSomeClass; ? - person Mirco; 27.07.2011
comment
@Mirco, нет, в этом нет ничего плохого. Единственное отличие состоит в том, что они будут созданы только тогда, когда вы сделаете на них фактическую ссылку в своем коде. В противном случае это прекрасно. - person iammilind; 27.07.2011
comment
Это не стандартный способ определения статического члена. Стандартным способом будет первый подход, который показывает ОП. Семантика этого фрагмента кода совершенно другая, вы определяете специализацию статической функции-члена, и это заставит вас определить такую ​​специализацию для каждого типа, создающего экземпляр, или вы получите ошибку компоновщика. - person David Rodríguez - dribeas; 27.07.2011
comment
@David, для твердого класса это один из способов, где вы можете явно определить. Первый подход также правильный (упомянул в своем комментарии); - person iammilind; 27.07.2011

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

Если все, что вы хотите достичь, это отдельный статический член, вам не нужен подкласс, вы можете просто создать экземпляр из TBase, и у них будет отдельный статический член, потому что каждый класс шаблона, сгенерированный из шаблона, имеет свои собственные копии любых статических переменных или участники, см. пример ниже (пример отлично компилируется с VS2008 и gcc):

struct CSomeClass {
    CSomeClass(int i):m_i(i){}
    int m_i;
};

template<class T_CLASS>
class TBase
{
  protected:
    static CSomeClass m_objSomeClass;

  public:
    inline void Set(CSomeClass f_objSomeClass) { m_objSomeClass = f_objSomeClass; }
};

class CSub1
{

};

class CSub2
{
};

template<class T_CLASS>
CSomeClass TBase<T_CLASS>::m_objSomeClass = CSomeClass(0);

int main()
{
    TBase<CSub1> tb1;
    TBase<CSub2> tb2;

    //tb1 and tb2 have separate static member after instantiated from tempalte class TBase
    tb1.Set(CSomeClass(1)); //tb1::m_objSomeClass now is 1
    tb2.Set(CSomeClass(2)); //tb2::m_objSomeClass now is 2
}
person Gob00st    schedule 27.07.2011

Мирко, поскольку вам действительно нужен подкласс, я пересмотрел свой пример, чтобы у вас был подкласс и отдельная статическая функция-член, см. ниже (пример отлично компилируется с VS2008 и gcc):

struct CSomeClass {
    CSomeClass(int i):m_i(i){}
    int m_i;
};

template<class T_CLASS>
class TBase
{
  protected:
    static CSomeClass m_objSomeClass;

  public:
    inline void Set(CSomeClass f_objSomeClass) { m_objSomeClass = f_objSomeClass; }
};

class CSub1 : public TBase<CSub1>
{

};

class CSub2 : public TBase<CSub2>
{
};

template<class T_CLASS>
CSomeClass TBase<T_CLASS>::m_objSomeClass = CSomeClass(0);

int main()
{
    TBase<CSub1> tb1;
    TBase<CSub2> tb2;

    //tb1 and tb2 have separate static member after instantiated from tempalte class TBase
    tb1.Set(CSomeClass(1)); //tb1::m_objSomeClass now is 1
    tb2.Set(CSomeClass(2)); //tb2::m_objSomeClass now is 2
}
person Gob00st    schedule 27.07.2011