Инициализация статического указателя в шаблонном классе - PullRequest
2 голосов
/ 04 августа 2010

Рассмотрим класс примерно так:

template < class T >
class MyClass
{
  private:
    static T staticObject;
    static T * staticPointerObject;
};
...
template < class T >
T MyClass<T>::staticObject; // <-- works
...
template < class T >
T * MyClass<T>::staticPointerObject = NULL; // <-- cannot find symbol staticPointerObject.

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

Приведенный выше код указан в заголовке, и проблема, о которой я говорил, - ошибка в шаге ссылки, поэтому он не находит определенный символ.

Ответы [ 5 ]

2 голосов
/ 04 августа 2010

«Не удается найти символ staticPointerObject» - это похоже на сообщение об ошибке linker . Это? (Подобные детали должны быть указаны в вашем вопросе).

Если это так, то, скорее всего, это произойдет, потому что вы поместили определения ваших статических элементов в файл реализацию (файл .cpp). Для того, чтобы это работало правильно, определения должны быть помещены в заголовочный файл (файл .h).

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

1 голос
/ 31 декабря 2011

Я подозреваю, что причиной вашего первого примера является следующий (из документа C ++ 2003 std).Обратите особое внимание на последнее предложение - из вашего примера, кажется, нет ничего, «что требует определения члена для существования».

14.7.1 Неявная реализация [temp.inst] 1 Если только шаблон классаспециализация была явно создана (14.7.2) или явно специализирована (14.7.3), специализация шаблона класса неявно создается, когда на специализацию ссылаются в контексте, который требует полностью определенного типа объекта или когда полнота типа классавлияет на семантику программы.Неявная реализация специализации шаблона класса вызывает неявную реализацию объявлений, но не определений или аргументов по умолчанию, функций-членов класса, классов-членов, статических членов-данных и шаблонов элементов;и это вызывает неявную реализацию определений членских анонимных союзов.Если элемент шаблона класса или шаблон элемента не был явно создан или явно специализирован, специализация члена создается неявно, когда на специализацию ссылаются в контексте, который требует определения элемента;в частности, инициализация (и любые связанные побочные эффекты) элемента статических данных не происходит, если только сам элемент статических данных не используется таким образом, который требует определения элемента статических данных.

0 голосов
/ 20 февраля 2011

Я все время использую следующий трюк. Идея состоит в том, чтобы поместить вашу статику в функцию и получать к ней доступ только из этой функции. Этот подход также позволяет избежать необходимости объявлять статические данные в файле .cpp - все может храниться в файле .h. После вашего примера кода:

template < class T >
class MyClass
{
  public:
    static T * getObject() {
      // Initialization goes here.
      static T * object = NULL; // or whatever you want
      return pointerObject;
    }
};
0 голосов
/ 04 августа 2010

Ваше первое «определение» статического члена - это всего лишь декларация - вот цитата из стандарта.

15 Явная специализация статического члена данных шаблона - это определение, еслидекларация включает инициализатор;в противном случае это декларация.[Примечание: нет синтаксиса для определения статического члена данных шаблона, который требует инициализации по умолчанию.шаблон <> X Q :: x;Это объявление независимо от того, может ли X быть инициализирован по умолчанию (8.5).]

Второе определение должно работать.Вы уверены, что у вас есть все в одном модуле компиляции?Что такое точный текст сообщения об ошибке?

Следующие компиляции / запуска с G ++ - все в одном файле

#include <iostream>

template < class T >
class MyClass
{
  public:
    static T staticObject;
    static T * staticPointerObject;
};

template < class T >
T MyClass<T>::staticObject;

template < class T >
T * MyClass<T>::staticPointerObject = 0; 

int main(int argc, char **argv)
{
  int an_int = 5;
  MyClass<int>::staticPointerObject = &an_int;
  std::cout << *MyClass<int>::staticPointerObject << std::endl;

  char a_char = 'a';
  MyClass<char>::staticPointerObject = &a_char;
  std::cout << *MyClass<char>::staticPointerObject << std::endl;
}
0 голосов
/ 04 августа 2010

Я нашел два решения.Ни один из них не является на 100% тем, на что я надеялся.

  1. Явная инициализация конкретного экземпляра, например

    int * MyClass<int>::staticPointerObject = NULL;

Это не удобноособенно когда у меня много разных типов.

Обернуть указатель внутри класса, например

    template < class T >   
    class MyClass   
    {   
      private:   
        struct PointerWrapper   
        {   
          T * pointer;   
          PointerWrapper( void )   
            : pointer( NULL )   
          { }   
        };   
        T staticObject;   
        PointerWrapper staticPointerObject;   
    };   
    ...   
    template < class T >   
    T MyClass<T>::staticObject; // <-- works fine.   
    ...   
    template < class T >   
    MyClass<T>::PointerWrapper MyClass<T>::staticPointerObject; // <-- works fine.

Это немного хлопотно, но по крайней мере пригодно для использования.Почему я могу создать экземпляр объекта переменной, но не указатель на объект переменной?Во всяком случае, я думаю, что у меня было бы больше проблем с другой стороны (компилятор заранее знает, как выглядит указатель, но не как мой объект).

Если у кого-то есть лучший ответ, яОчень хотелось бы увидеть это!

...