Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Erop, Вы писали:
E>По идее должно работать уже это: E>Но, похоже, в gcc какая-то ошибка на эту тему. E>Когда ты добавляешь extern, gcc, похоже, воспринимает это как какое-то хитрое объявление, а не определение. E>Попробуй написать так:
Здравствуйте, Molchalnik, Вы писали: M>Кодт, то, что ты написал в примере, красиво и понятно, я это знаю и так и делаю. Так ведь не работает же! Должно работать в теории, но не работает. Точнее, работает, пока cpp файл один. Как только начинаешь обращаться к инстанции шаблонного класса из двух cpp (или даже из одного, но не того, в котором дано определение статического члена-данного шаблонного класса), начинается разнообразная хрень. Написали здесь много чего, но ответа на свой вопрос я так не получил. У меня gcc 4.7.2 для убунты, возможно, это фишка или баг gcc
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Приведи полный код примера. На самом старом GCC который есть под рукой — 4.1.2, работает без (0)
Понятно, что и без (0) должно, просто это вариант обойти багу.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Erop, Вы писали:
EP>>Приведи полный код примера. На самом старом GCC который есть под рукой — 4.1.2, работает без (0) E>Понятно, что и без (0) должно, просто это вариант обойти багу.
Я пытаюсь понять на каком примере и на каком компиляторе у тебя вылез такой баг.
Re[5]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Я пытаюсь понять на каком примере и на каком компиляторе у тебя вылез такой баг.
У меня не вылез...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, B0FEE664, Вы писали:
BFE> BFE>Всё работает:
Ога, так всё работает. Просто не надо объявлять статическую переменную в cpp. или объявлять в обоих. Я так тоже пробовал, но почему-то "не пошло". Может, это был баг gcc, но я думаю, просто накосячил где-то. Теперь всё работает. Спасибо.
Re[6]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Erop, Вы писали:
EP>>Я пытаюсь понять на каком примере и на каком компиляторе у тебя вылез такой баг. E>У меня не вылез...
Ну так между тем что ты показал и тем что сделал ТС — разница в одно определение (точнее оно было, но не в заголовке, а в одном из TU. причём, как я понял, в том TU не было нужных instatiations, а в том TU где использовалось — не было видно определения)
То есть там баг в коде, а не в GCC.
Re[7]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ну так между тем что ты показал и тем что сделал ТС — разница в одно определение (точнее оно было, но не в заголовке, а в одном из TU. причём, как я понял, в том TU не было нужных instatiations, а в том TU где использовалось — не было видно определения)
Точно так. А когда я сделал так, как показал B0FEE664, я накосячил, и у меня вылез баг, и я запихнул определение в cpp. У меня всё заработало и я забил. А потом появилось обращение из другого cpp, и началась ерунда.
Но просветление не наступило. Я не получил ответа на свой вопрос, если не считать Кодта с его ODR. Просветление — это понимание не на уровне "ты туда ходи, а не сюда" "определяй статический шаблон в хедере, а не в сипипи", а понимание на уровне принципов.
Я понимаю, что хедер тупо вставляется в cpp, и никакого хедера для компилера на самом деле нет ( "ложки нет"(С) ). В результате после инклюда компилер имеет два сипипи с длинной простынёй одинаковых определений шаблонов, стандартных и созданных программистом. Если статическая переменная шаблона объявлена в неком cpp, то она не объявлена в другом cpp.
Так вот, почему просто статическую переменную можно определить в одном cpp, а статическую переменную шаблона нужно определять в каждом cpp, или, что одно и тоже, в хедере?
Re[8]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Molchalnik, Вы писали:
M>Так вот, почему просто статическую переменную можно определить в одном cpp, а статическую переменную шаблона нужно определять в каждом cpp, или, что одно и тоже, в хедере?
у Widget<int> будет своя статическая переменная, у Widget<double> — своя.
Когда
template<typename T> Gadget Widget<T>::x;
есть только в одном translation unit — он инстанциирует static member только для тех вариантов Widget<???> которые сам использует.
Он ничего не знает про то, какие Widget<???> используются в других TU. А инстанциировать для всех возможных типов Widget<???> он не может, так как их бесконечно много.
Re[9]: Ещё один вопрос про определение статического члена шаблонного класса
EP>Он ничего не знает про то, какие Widget<???> используются в других TU. А инстанциировать для всех возможных типов Widget<???> он не может, так как их бесконечно много.
Пример для большего понимания:
$ find ./ -type f | xargs -i% sh -c "echo ________[%]________ && cat %"
________[./main.cpp]________
#include"t.h"int main()
{
int x = Widget<int>::x.value;
int y = Widget<double>::x.value;
}
________[./t.cpp]________
#include"t.h"template<typename T> Gadget Widget<T>::x;
void foo()
{
int x = Widget<int>::x.value;
}
________[./t.h]________
struct Gadget { int value; };
template<typename T>
struct Widget
{
static Gadget x;
};
$ g++ main.cpp t.cpp
main.cpp:(.text+0x18): undefined reference to `Widget<double>::x'
Как видно, ругается только на отсутствие Widget<double>::x, но не Widget<int>::x — так как Widget<int>::x инстанциировался в t.cpp.
Но t.cpp ничего не знает про то, что main.cpp нужен Widget<double>::x.
Re[9]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>[/ccode] есть только в одном translation unit — он инстанциирует static member только для тех вариантов Widget<???> которые сам использует. EP>Он ничего не знает про то, какие Widget<???> используются в других TU. А инстанциировать для всех возможных типов Widget<???> он не может, так как их бесконечно много.
А как компилер поступает (и как должен поступать), если в двух TU используется одна и таже инстанция шаблона, например, Widget<int> ?
Как-то же он линкует статические данные Widget<int>::x, чтобы в двух модулях они были одной и той же переменной, а не двумя разными
Re[10]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Molchalnik, Вы писали:
M>А как компилер поступает (и как должен поступать), если в двух TU используется одна и таже инстанция шаблона, например, Widget<int> ? M>Как-то же он линкует статические данные Widget<int>::x, чтобы в двух модулях они были одной и той же переменной, а не двумя разными
Примерно также как и с inline функциями — о чём и сказал Кодт в первом
If lowercase, the symbol is usually local; if uppercase, the symbol is global (external). There are however a few lowercase symbols that are shown for special global symbols (u, v and w).
...
B
b
The symbol is in the uninitialized data section (known as BSS).
...
u
The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process there is just one symbol with this name and type in use.
Re[11]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Molchalnik, Вы писали:
M>Я понимаю, что хедер тупо вставляется в cpp, и никакого хедера для компилера на самом деле нет ( "ложки нет"(С) ). В результате после инклюда компилер имеет два сипипи с длинной простынёй одинаковых определений шаблонов, стандартных и созданных программистом. Если статическая переменная шаблона объявлена в неком cpp, то она не объявлена в другом cpp.
А ты говоришь, просветление не наступило.
M>Так вот, почему просто статическую переменную можно определить в одном cpp, а статическую переменную шаблона нужно определять в каждом cpp, или, что одно и тоже, в хедере?
Потому что определение члена шаблона — это, на самом деле, шаблон определения члена. (Неважно, статическая переменная или функция).
Определением конкретного символа линковки (как это по-рюсски, в терминах стандарта?) он становится только при воплощении (instantiation) — явном или по факту использования.
Отвлечёмся от статических членов — пусть будут свободные функции
//////////
// x.cpptemplate<class T> void foo(); // объявлениеvoid x() { foo<int>(); foo<char>(); } // для линкера - ссылки на foo<int>, foo<char>
//////////
// y.cpptemplate<class T> void foo(); // объявлениеtemplate<class T> void foo() {} // определениеvoid y() { foo<int>(); foo<short>(); } // для линкера - ссылки на foo<int>, foo<char>, плюс созданы соответствующие воплощенияtemplate void foo<long>(); // создано, но не используется воплощение foo<long>
При линковке — линкер будет искать foo<int>, foo<char>, foo<short> и найдёт foo<int>, foo<short>, foo<long>.
Перекуём баги на фичи!
Re[9]: Ещё один вопрос про определение статического члена шаблонного класса
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Molchalnik, Вы писали:
M>>Я понимаю, что хедер тупо вставляется в cpp, и никакого хедера для компилера на самом деле нет ( "ложки нет"(С) ). В результате после инклюда компилер имеет два сипипи с длинной простынёй одинаковых определений шаблонов, стандартных и созданных программистом. Если статическая переменная шаблона объявлена в неком cpp, то она не объявлена в другом cpp.
К>А ты говоришь, просветление не наступило.
Так это я уже десять лет как знаю.
К>Потому что определение члена шаблона — это, на самом деле, шаблон определения члена. (Неважно, статическая переменная или функция). К>Определением конкретного символа линковки (как это по-рюсски, в терминах стандарта?) он становится только при воплощении (instantiation) — явном или по факту использования.
Спасибо, одна моя ладонь хлопнула. Просветление меня настигло. Мне как раз и надо было описание ситуации в терминах стандарта и с точки зрения компилера/линкера