Ещё один вопрос про определение статического члена шаблонного класса
От: Molchalnik  
Дата: 10.10.13 12:45
Оценка:
Есть один заголовочник и два cpp

В заголовочнике задан шаблонный класс со статическим членом, тип члена задан в том же классе (как показали эксперименты, это важно).

вот код заголовочника, который воспроизвёл ситуацию на простейшем примере:

//header.h
template <typename Arg> class Ft {
 public:
  typedef std::vector<Arg> VectorT;
  static VectorT p_;
};



В одном cpp он определён (без инициализации)

//1.cpp
#include "header.h"
template <typename Arg> std::vector<int> Ft<Arg>::p_;



Второй cpp обращается к классу, и косвенно, через методы класса, к статическому члену.


#include "Header.h"

class XFt {};

void SomeFunFt(Ft<int>& data) {
  data.p_.clear(); //здесь, правда, обращение не косвенно, но это же упрощённый пример
}



Компилятор (gcc) выдаёт ошибку, undefined reference

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


//header.h
template <typename Arg> class Ft {
 public:
  typedef std::vector<Arg> VectorT;
  static VectorT p_;
};

template <class Arg> extern typename Ft<Arg>::VectorT Ft<Arg>::p_;
, то всё прекрасно начинает работать.

При этом если не определять VectorT, а прописывать напрямую std::vector<Arg>, то всё работает совсем по другому и компилер начинает ругаться и на extern-объявление, и на обычное, а без них выдаёт вообще undefined reference и как это скомпилить — вообще не понятно.

Помогите достичь просветления.
Re: Ещё один вопрос про определение статического члена шаблонного класса
От: Кодт Россия  
Дата: 10.10.13 13:28
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Помогите достичь просветления.


Не ищи сложных путей,
не создавай трудности линкеру, с тем, чтобы потом их героически преодолевать,
не нарушай ODR (в первом случае ты создаёшь предпосылку: объявляешь vector<Arg> Ft<Arg>::p_, а определяешь vector<int> Ft<Arg>::p_).

Определение шаблона должно быть доступно всем.
И все, кому оно нужно, спровоцируют воплощения, а линкер сам разберётся, как избавиться от дубликатов — так же, как он избавляется от дубликатов инлайн-функций.
Перекуём баги на фичи!
Re[2]: Ещё один вопрос про определение статического члена шаблонного класса
От: Molchalnik  
Дата: 10.10.13 13:43
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Molchalnik, Вы писали:


M>>Помогите достичь просветления.


К>Не ищи сложных путей,

К>не создавай трудности линкеру, с тем, чтобы потом их героически преодолевать,
К>не нарушай ODR (в первом случае ты создаёшь предпосылку: объявляешь vector<Arg> Ft<Arg>::p_, а определяешь vector<int> Ft<Arg>::p_).

Так я бы и рад вообще оставить одно определение — которое внутри определения класса, так ведь не работает же!!! пишет — "undefined reference"!!!
Я вообще в шоке.
Re[3]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 14:18
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Здравствуйте, Кодт, Вы писали:


К>>Здравствуйте, Molchalnik, Вы писали:


M>>>Помогите достичь просветления.


К>>Не ищи сложных путей,

К>>не создавай трудности линкеру, с тем, чтобы потом их героически преодолевать,
К>>не нарушай ODR (в первом случае ты создаёшь предпосылку: объявляешь vector<Arg> Ft<Arg>::p_, а определяешь vector<int> Ft<Arg>::p_).

M>Так я бы и рад вообще оставить одно определение — которое внутри определения класса, так ведь не работает же!!! пишет — "undefined reference"!!!

M>Я вообще в шоке.

определи статического члена для специализации в cpp файле:

template<> vector<int> Ft<int>::_p;

и все ьудет нормально.
Re[4]: Ещё один вопрос про определение статического члена шаблонного класса
От: Molchalnik  
Дата: 10.10.13 14:35
Оценка:
Здравствуйте, andyp, Вы писали:


A>определи статического члена для специализации в cpp файле:


A>template<> vector<int> Ft<int>::_p;


A>и все ьудет нормально.


В примере — это легко... А в большом проекте хз чем может быть класс инициализирован

и...

если обращение к Ft<int> есть в обоих cpp файлов???
Re[3]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 14:39
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Здравствуйте, Кодт, Вы писали:


К>>Здравствуйте, Molchalnik, Вы писали:


M>>>Помогите достичь просветления.


К>>Не ищи сложных путей,

К>>не создавай трудности линкеру, с тем, чтобы потом их героически преодолевать,
К>>не нарушай ODR (в первом случае ты создаёшь предпосылку: объявляешь vector<Arg> Ft<Arg>::p_, а определяешь vector<int> Ft<Arg>::p_).

M>Так я бы и рад вообще оставить одно определение — которое внутри определения класса, так ведь не работает же!!! пишет — "undefined reference"!!!

M>Я вообще в шоке.

еще одна опция — оставить

template<typename T> vector<T> Ft<T>:_p

в хидере, но нигде не пользоваться explicit specialization для шаблона Ft (те не писать нигде
template class Ft<int>;
), а то порушишь ODR.
Re[5]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 14:47
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Здравствуйте, andyp, Вы писали:




M>В примере — это легко... А в большом проекте хз чем может быть класс инициализирован


M>и...


M>если обращение к Ft<int> есть в обоих cpp файлов???


так делать не надо совсем. Может оказаться так, что обратишься к p_ до вызова его конструктора.
Re[6]: Ещё один вопрос про определение статического члена шаблонного класса
От: Molchalnik  
Дата: 10.10.13 15:13
Оценка:
Здравствуйте, andyp, Вы писали:

M>>если обращение к Ft<int> есть в обоих cpp файлов???


A>так делать не надо совсем. Может оказаться так, что обратишься к p_ до вызова его конструктора.


?? т.е. шаблон со статическим членом нельзя использовать в двух cpp? Странно
Re[7]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 15:19
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>?? т.е. шаблон со статическим членом нельзя использовать в двух cpp? Странно


Шаблон не при делах. Попробуй поиспользовать значение глобальной переменной в глобальной переменной из другой единицы трансляции. Стандарт не специфицирует порядок инициалиации в таких случаях.
Re[8]: Ещё один вопрос про определение статического члена шаблонного класса
От: Molchalnik  
Дата: 10.10.13 15:21
Оценка:
Здравствуйте, andyp, Вы писали:

A>Здравствуйте, Molchalnik, Вы писали:


M>>?? т.е. шаблон со статическим членом нельзя использовать в двух cpp? Странно


A>Шаблон не при делах. Попробуй поиспользовать значение глобальной переменной в глобальной переменной из другой единицы трансляции. Стандарт не специфицирует порядок инициалиации в таких случаях.


но глобальную переменную можно объявить как extern
Re[3]: Ещё один вопрос про определение статического члена шаблонного класса
От: Кодт Россия  
Дата: 10.10.13 15:28
Оценка: 1 (1)
Здравствуйте, Molchalnik, Вы писали:

M>Так я бы и рад вообще оставить одно определение — которое внутри определения класса, так ведь не работает же!!! пишет — "undefined reference"!!!

M>Я вообще в шоке.

Внутри класса не определение, а объявление статического члена-данного.
Определение вовне, так же, как в нешаблонном классе.
Только слово extern не нужно.
template<class T>
struct Foo
{
  typedef vector<T> U;

  static U x;
  static int y;

  static const U cx;
  static const int cy = 123; // интегральные константы можно определять на месте

  // предвосхищая ещё вопросы по шаблонам...
  void bar();
  template<class Z> void buz();
};

template<class T> typename Foo<T>::U       Foo<T>::x;       // с дефолтным конструктором
template<class T> int                      Foo<T>::y  = 42; // инициализация присваиванием (конструктор копирования)
template<class T> typename Foo<T>::U const Foo<T>::cx (10); // с недефолтным конструктором

template<class T>                   void   Foo<T>::bar() {}
template<class T> template<class Z> void   Foo<T>::buz() {}
Перекуём баги на фичи!
Re[9]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 15:32
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>но глобальную переменную можно объявить как extern

в extern нет нужды. у глобальных переменных в cpp (также как и static data members класса) по умолчанию external linkage.
Re: Ещё один вопрос про определение статического члена шаблонного класса
От: B0FEE664  
Дата: 10.10.13 15:34
Оценка: +1
Здравствуйте, Molchalnik, Вы писали:

M>
M>//header.h
M>template <typename Arg> class Ft {
M> public:
M>  typedef std::vector<Arg> VectorT;
M>  static VectorT p_;
M>};

M>template <class Arg> extern typename Ft<Arg>::VectorT Ft<Arg>::p_;
M>
, то всё прекрасно начинает работать.


А зачем тут extern? Без него всё должно работать.

M>Помогите достичь просветления.


Что не ясно-то?
И каждый день — без права на ошибку...
Re[4]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 15:35
Оценка:
Здравствуйте, Кодт, Вы писали:


К>

К>template<class T> typename Foo<T>::U       Foo<T>::x;       // с дефолтным конструктором

К>


Кодт, тут тонкость одна есть — обязательно нужно равно после х. Иначе компилятор не сможет различить объявление от определения (поправьте, если не прав) и будет как раз undefined reference.
Re[2]: Ещё один вопрос про определение статического члена шаблонного класса
От: Molchalnik  
Дата: 10.10.13 16:15
Оценка:
Здравствуйте, B0FEE664, Вы писали:


BFE>А зачем тут extern? Без него всё должно работать.


Вот и я думаю — а зачем здесь extern? и без него должно работать

M>>Помогите достичь просветления.


BFE>Что не ясно-то?

почему не работает без extern, почему не работает с объявлением статического члена в cpp, если ссылка на инстанцию шаблона есть в другом cpp

Хотя должно вроде работать, вот и Кодт написал, однако же...
Re[5]: Ещё один вопрос про определение статического члена шаблонного класса
От: enji  
Дата: 10.10.13 16:37
Оценка:
Здравствуйте, andyp, Вы писали:

К>>

К>>template<class T> typename Foo<T>::U       Foo<T>::x;       // с дефолтным конструктором

К>>


A>Кодт, тут тонкость одна есть — обязательно нужно равно после х. Иначе компилятор не сможет различить объявление от определения (поправьте, если не прав) и будет как раз undefined reference.


Не прав. Тут же имя класса участвует, таких объявлений не бывает.

class A{};
int A::a; // это не объявление, а ошибка компиляции
Re[6]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 16:59
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, andyp, Вы писали:


К>>>

К>>>template<class T> typename Foo<T>::U       Foo<T>::x;       // с дефолтным конструктором

К>>>


A>>Кодт, тут тонкость одна есть — обязательно нужно равно после х. Иначе компилятор не сможет различить объявление от определения (поправьте, если не прав) и будет как раз undefined reference.


E>Не прав. Тут же имя класса участвует, таких объявлений не бывает.


E>
E>class A{};
E>int A::a; // это не объявление, а ошибка компиляции
E>
Re[6]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 17:01
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, andyp, Вы писали:


К>>>

К>>>template<class T> typename Foo<T>::U       Foo<T>::x;       // с дефолтным конструктором

К>>>


A>>Кодт, тут тонкость одна есть — обязательно нужно равно после х. Иначе компилятор не сможет различить объявление от определения (поправьте, если не прав) и будет как раз undefined reference.


E>Не прав. Тут же имя класса участвует, таких объявлений не бывает.


E>
E>class A{};
E>int A::a; // это не объявление, а ошибка компиляции
E>


как же быть тогда с вот этим ?
Re[7]: Ещё один вопрос про определение статического члена шаблонного класса
От: andyp  
Дата: 10.10.13 17:31
Оценка:
A>как же быть тогда с вот этим ?

вопрос снят. это касается только explicit instantiation
Re[4]: Ещё один вопрос про определение статического члена шаблонного класса
От: Molchalnik  
Дата: 11.10.13 05:44
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Molchalnik, Вы писали:




К>Внутри класса не определение, а объявление статического члена-данного.

К>Определение вовне, так же, как в нешаблонном классе.
К>Только слово extern не нужно.

Кодт, то, что ты написал в примере, красиво и понятно, я это знаю и так и делаю. Так ведь не работает же! Должно работать в теории, но не работает. Точнее, работает, пока cpp файл один. Как только начинаешь обращаться к инстанции шаблонного класса из двух cpp (или даже из одного, но не того, в котором дано определение статического члена-данного шаблонного класса), начинается разнообразная хрень. Написали здесь много чего, но ответа на свой вопрос я так не получил. У меня gcc 4.7.2 для убунты, возможно, это фишка или баг gcc


Я работаю с шаблонами многие годы, пишу иногда очень сложные вещи, но такое — впервые. Я не считаю себя гуру, т.к. знаю C++ по книгам, а не по заученным пунктам стандарта (а без этого, в моём понимании, гуру не гуру), но для своих коллег я вполне сойду за гуру, если речь пойдёт о шаблонах. И тем не менее, в чём-то простом и известном и понятном для меня у меня выходит чёрти что. Значит, у меня либо пробел в понимании, либо я где-то очень глупо и по-дурацки протупил, либо это баг gcc. В любом случае буду рад помощи.

Опять же, отсутствие глубокого знания стандарта в наше время, когда компиляторы приближаются к стандарту всё больше и больше, становится фатальным багом — то, что работало раньше из-за низкой совместимости с C++98 standard теперь не работает из-за высокой совместимости с c++11 standard

з.ы. проект C++11
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.