Здравствуйте, Аноним, Вы писали:
А>Занятная штука:
А>template<typename T> А>class counter{ А> static <b>T</b> cnt; А>public: А> counter(){ А> cnt++; А> }
А> ~counter(){ А> cnt--; А> } А>};
А>template<typename T> А><b>int</b> counter<T>::cnt = 0;
А>В функции main: А>counter<int> i; А>counter<int> j;
А>counter<float> f; //Понятно, ошибка C2371: 'cnt' : redefinition; different basic types
обращаем внимание на выделенный текст и все действительно становится понятным...
А>Так как быть с шаблонными классами и статическими элементами??
думается мне счеткик таки должен быть int... в таком случае все работает...
Здравствуйте, zaufi, Вы писали:
Z>Здравствуйте, Аноним, Вы писали:
А>>Занятная штука:
А>>template<typename T> А>>class counter{ А>> static T cnt; А>>public: А>> counter(){ А>> cnt++; А>> }
А>> ~counter(){ А>> cnt--; А>> } А>>};
А>>template<typename T> А>>[b]int[/b>]counter<T>::cnt = 0;
А>>В функции main: А>>counter<int> i; А>>counter<int> j;
А>>counter<float> f; //Понятно, ошибка C2371: 'cnt' : redefinition; different basic types Z>обращаем внимание на выделенный текст и все действительно становится понятным...
непрально выделел текст ))
А>>Так как быть с шаблонными классами и статическими элементами?? Z>думается мне счеткик таки должен быть int... в таком случае все работает...
собственно даже если счетчик буит иметь тип T все также буит работать...
это плохо без особой нужды использовать статические в функции. Это всё равно что добавить if (true) который никогда не вырежит компилятор. И должно быть оправдание для такого действия.
Здравствуйте, Caracrist, Вы писали:
C>Здравствуйте, ffk, Вы писали:
ffk>>Здравствуйте, Аноним, Вы писали:
А>>>Занятная штука:
А>>>template<typename T> А>>>class counter{ А>>> //static T cnt; А>>>public: А>>> counter(){ А>>> cnt()++; А>>> }
А>>> ~counter(){ А>>> cnt()--; А>>> } A>>>private: A>>> int& cnt() {static int cnt_ = 0; return cnt;} ffk>>А>};
C>это плохо без особой нужды использовать статические в функции. Это всё равно что добавить if (true) который никогда не вырежит компилятор. И должно быть оправдание для такого действия.
В 99.99% это пофиг, даже не заметешь.
Критикуешь, предложи более красивое решение.
Здравствуйте, ffk, Вы писали:
ffk>Здравствуйте, Caracrist, Вы писали:
ffk>В 99.99% это пофиг, даже не заметешь. ffk>Критикуешь, предложи более красивое решение.
template<typename T>
class counter{
static int cnt;public:
counter(){
cnt++;
}
~counter(){
cnt--;
}
// тут гдето должны быть публичные функции или friends иначе этот счётчик никогда никто не прочтёт
};
template<typename T>
int counter<T>::cnt = 0;
Здравствуйте, Caracrist, Вы писали:
C>в целом оно выглядит вот так: C>
C>template<typename T>
C>class counter{
C>static int cnt;
C>public:
C>counter(){
C>cnt++;
C>}
C>~counter(){
C>cnt--;
C>}
C>// тут гдето должны быть публичные функции или friends иначе этот счётчик никогда никто не прочтёт
C>};
C>template<typename T>
C>int counter<T>::cnt = 0;
C>
C>простота залог успеха
Насколько успешно такой хидер может быть включён в несколько единиц трансляции? Без использования __declspec(selectany)
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
C>>template<typename T>
C>>class counter{
C>>static int cnt;
C>>public:
C>>counter(){
C>>cnt++;
C>>}
C>>~counter(){
C>>cnt--;
C>>}
C>>// тут гдето должны быть публичные функции или friends иначе этот счётчик никогда никто не прочтёт
C>>};
C>>template<typename T>
C>>int counter<T>::cnt = 0;
C>>
C>>простота залог успеха
GN>Насколько успешно такой хидер может быть включён в несколько единиц трансляции? Без использования __declspec(selectany)
PUBLIC ?f@@YAPAXXZ ; f
; Function compile flags: /Odtp
; File t2.cpp
_TEXT SEGMENT
_p$ = -4 ; size = 4
?f@@YAPAXXZ PROC ; f
; 7 : {
push ebp
mov ebp, esp
sub esp, 8
; 8 : counter <int> c;
; 9 : void* volatile p = &c.cnt;
mov DWORD PTR _p$[ebp], OFFSET ?cnt@?$counter@H@@2HA ; counter<int>::cnt
; 10 : return p;
mov eax, DWORD PTR _p$[ebp]
; 11 : }
mov esp, ebp
pop ebp
ret 0
?f@@YAPAXXZ ENDP ; f
END
Остаётся угадать, что за адреса будут присвоены p в первый и второй разы.
Впринципе, предпосылки для разрешения
template<typename T> int counter<T>::cnt;
понятны, непонятно, почему инстанциация
template<> int counter<int>::cnt;
ведёт себя отлично от 9.4.2/5 (There shall be exactly one definition of a static data member that is used in a program; no diagnostic is required; see 3.2.).
Шаблон класса — семейство классов, а полная специализация не может считаться "отдельным" классом, это всё равно какое-то семейство?
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[8]: Чем статические данные отличаются от методов?
Здравствуйте, gear nuke, Вы писали:
GN>Здравствуйте, Andrew S, Вы писали:
AS>>А что, есть сомнения?
GN>Да, есть. Не могу найти, где это разрешено в Стандарте.
В принципе, есть похожие объекты -- это шаблоны функций и методов. Где, например, написано про них?
GN>
Вообще-то этот код нарушает ODR, так что последствия могут быть любы...
GN>Впринципе, предпосылки для разрешения GN>
GN>template<typename T> int counter<T>::cnt;
GN>
GN>понятны, непонятно, почему инстанциация GN>
GN>template<> int counter<int>::cnt;
GN>
ведёт себя отлично от 9.4.2/5 (There shall be exactly one definition of a static data member that is used in a program; no diagnostic is required; see 3.2.).
А разве в твоём примере была где-то явная инстанциация? А неявные ведут себя не так. Например шаблоны методов ты же описываешь в хедере, рядом с шаблоном класса, и в каждой TU получается своя неявная инстанциация, и ничего, линкуется всё как-то...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Чем статические данные отличаются от методов?
Здравствуйте, Erop, Вы писали:
E>В принципе, есть похожие объекты -- это шаблоны функций и методов. Где, например, написано про них?
Можно иметь 2 копии одной функции и вызывать их из разных мест — наблюдаемое поведение не изменится. Если имеется 2 копии одного объекта, то это подразумевает возможность хранения разных состояний, что и демонстрирует мой пример.
GN>>
E>Вообще-то этот код нарушает ODR, так что последствия могут быть любы...
А чем принципиально этот код отличается от исходного? Тем, что значения разные Обрати внимание на директиву PUBLIC в асм листинге — это внешнее связывание, сохранится если убрать мои изменения.
E>А разве в твоём примере была где-то явная инстанциация?
Не было, но если исправить — результат не изменится.
E> А неявные ведут себя не так. Например шаблоны методов ты же описываешь в хедере, рядом с шаблоном класса, и в каждой TU получается своя неявная инстанциация, и ничего, линкуется всё как-то...
Не пойму, почему проводится аналогия с функциями. Это не первокласные объекты. По-моему аналогия со статическими членами-данными не шаблонных классов более уместна (интуитивна).
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[10]: Чем статические данные отличаются от методов?
Здравствуйте, gear nuke, Вы писали:
GN>Можно иметь 2 копии одной функции и вызывать их из разных мест — наблюдаемое поведение не изменится.
Во-первых, это очень расточительно. Прикинь, весь STL тянулся бы во все TU, например
GN>Если имеется 2 копии одного объекта, то это подразумевает возможность хранения разных состояний, что и демонстрирует мой пример.
Во-вторых, вообще нельзя, так как изменится и наблюдаемое поведение, по крайней мере из-за того, что существуют
1) static in function
2) указатели на функции
E>>Вообще-то этот код нарушает ODR, так что последствия могут быть любы... GN>А чем принципиально этот код отличается от исходного? Тем, что значения разные Обрати внимание на директиву PUBLIC в асм листинге — это внешнее связывание, сохранится если убрать мои изменения.
Тем, что в исходном переменная имеет одно определение...
GN>Не было, но если исправить — результат не изменится.
Ну и так и сяк некорректно всё, потому, что ODR нарушено -- есть несколько неэквивалентных определений одного объекта.
Кроме того, если ты явно инстанцируешь что-то, то, AFAIK, это нужно делать только в одной TU... Так что, по идее, "если исправить", то IMHO, не слинкуется...
E>> А неявные ведут себя не так. Например шаблоны методов ты же описываешь в хедере, рядом с шаблоном класса, и в каждой TU получается своя неявная инстанциация, и ничего, линкуется всё как-то...
GN>Не пойму, почему проводится аналогия с функциями. Это не первокласные объекты. По-моему аналогия со статическими членами-данными не шаблонных классов более уместна (интуитивна).
Зато указатеои на них, вполне себе первоклассные. И гарантируется, что в какой TU указатель на функцию не возьми, во всех совпадут указатели на одну и ту же функцию...
Короче говоря. Определять шаблоном статические переменные -- это общепринято. Так что если это от чего-то не разрешено в стандарте, то это баг стандарта
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Чем статические данные отличаются от методов?
Здравствуйте, gear nuke, Вы писали:
GN>Здравствуйте, Erop, Вы писали:
E>>В принципе, есть похожие объекты -- это шаблоны функций и методов. Где, например, написано про них?
GN>Можно иметь 2 копии одной функции и вызывать их из разных мест — наблюдаемое поведение не изменится.
template<typename T>
struct S
{
void myFunc()
{
static int oproverzhenie;
// blablabla
}
};
Здравствуйте, Erop, Вы писали:
GN>>Можно иметь 2 копии одной функции и вызывать их из разных мест — наблюдаемое поведение не изменится. E>Во-первых, это очень расточительно. Прикинь, весь STL тянулся бы во все TU, например
В случае с функциями транслятор может сравнить например их AST и убрать лишнюю копию.
GN>>Если имеется 2 копии одного объекта, то это подразумевает возможность хранения разных состояний, что и демонстрирует мой пример.
E>Во-вторых, вообще нельзя, так как изменится и наблюдаемое поведение, по крайней мере из-за того, что существуют E>1) static in function E>2) указатели на функции
А зачем они тогда приводились как пример?
E>>>Вообще-то этот код нарушает ODR, так что последствия могут быть любы... GN>>А чем принципиально этот код отличается от исходного? Тем, что значения разные Обрати внимание на директиву PUBLIC в асм листинге — это внешнее связывание, сохранится если убрать мои изменения.
E>Тем, что в исходном переменная имеет одно определение...
Она имеет 2 одинаковых определения в разных TU.
GN>>Не было, но если исправить — результат не изменится. E>Ну и так и сяк некорректно всё, потому, что ODR нарушено -- есть несколько неэквивалентных определений одного объекта. E>Кроме того, если ты явно инстанцируешь что-то, то, AFAIK, это нужно делать только в одной TU... Так что, по идее, "если исправить", то IMHO, не слинкуется...
Слинкуется. Я проверял, ассемблерные листинги не меняются.
E>>> А неявные ведут себя не так. Например шаблоны методов ты же описываешь в хедере, рядом с шаблоном класса, и в каждой TU получается своя неявная инстанциация, и ничего, линкуется всё как-то...
А тут имеет место быть ослабление ODR за счёт inline.
GN>>Не пойму, почему проводится аналогия с функциями. Это не первокласные объекты. По-моему аналогия со статическими членами-данными не шаблонных классов более уместна (интуитивна). E>Зато указатеои на них, вполне себе первоклассные. И гарантируется, что в какой TU указатель на функцию не возьми, во всех совпадут указатели на одну и ту же функцию...
Ну ок, пусть нет разницы между указателями на объекты и функции. Тогда мой пример показывает что гарантии нарушаются
E>Короче говоря. Определять шаблоном статические переменные -- это общепринято. Так что если это от чего-то не разрешено в стандарте, то это баг стандарта
Про const static соглашусь. В остальных случаях баг может пролезть в результат.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[11]: Чем статические данные отличаются от методов?
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[11]: Чем статические данные отличаются от методов?
Здравствуйте, Erop, Вы писали:
E>в исходном переменная имеет одно определение...
Может быть вот такое "одно" определение в хидере:
template<typename T>
int counter<T>::cnt = __COUNTER__;
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[12]: Чем статические данные отличаются от методов?
тем, что сдесь оно без контекста и демонстрирует принципиальную возможность того, что "наблюдаемое поведение да изменится"
А то что ни в каких случаях, ни за что не оправдано использование статиков в функциях, я не говорил.
Во-первых, __COUNTER__ в разных TU считает независимо.
Во-вторых, или и заботай ODR, что ли. Для всяких объектов с ослабленным ODR, вроде inline-функций и т. п. требуют, чтобы определения присутствующие во всех TU были эквивалентны...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: Чем статические данные отличаются от методов?
Здравствуйте, gear nuke, Вы писали:
GN>В случае с функциями транслятор может сравнить например их AST и убрать лишнюю копию.
Что мешает сравнить определения статического члена?
Кроме того, обычно лишнюю копию выбрасывает линкер, а не компилятор...
GN>А зачем они тогда приводились как пример?
Затем, что всегда можно написать так например:
// 0.htemplate<typename T> T foo( T t ) { return t; }
typedef int int2int( int );
extern int2int* getFooPtr();
//1.cpp#include"0.h"extern int2int* getFooPtr()
{
return foo<int>;
}
//2.cpp#include"0.h"void bar()
{
assert( getFooPtr() == &foo<int> );
}
GN>Она имеет 2 одинаковых определения в разных TU.
Изучи как так получается, что inline-функции не противоречат ODR...
GN>Слинкуется. Я проверял, ассемблерные листинги не меняются.
Пример приведи, что именно исправлял? Было два cpp с кодом
template<> int xxx<int>::counter = 10;
и
template<> int xxx<int>::counter = 20;
GN>А тут имеет место быть ослабление ODR за счёт inline.
ОТкуда inline в коде
template<typename T> T foo( T t ) { return t; }
Но ты кое в чём прав. Ослабление ODR таки имеет место. Но оно бывает не только для inline, но и для разных других данных и кода. Например для таблицы виртуальных функций класса или для результатов неявной инстанциации шаблонов...
GN>Ну ок, пусть нет разницы между указателями на объекты и функции. Тогда мой пример показывает что гарантии нарушаются
Ничего не нарушается. В твоём примере нарушено ODR! Даже ослабленное. Это снимает ответственность за последствия с авторов транслятора!
GN>Про const static соглашусь. В остальных случаях баг может пролезть в результат.
Нет. Не const тоже. Вообще-то если статическое поле имеет нетривиальные конструктор или деструктор, то пофиг const оно или не сonst...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: Чем статические данные отличаются от методов?
хуже? Оно будет работать и для не-шаблонов.
GN>>Она имеет 2 одинаковых определения в разных TU. E>Изучи как так получается, что inline-функции не противоречат ODR...
Получается как в стандарте:
3.2/3 Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is used.
GN>>Слинкуется. Я проверял, ассемблерные листинги не меняются. E>Пример приведи, что именно исправлял? Было два cpp с кодом
template<> int xxx<int>::counter = 10;
и
template<> int xxx<int>::counter = 20;
Да, так и было, только значения другие.
E>Ничего не нарушается. В твоём примере нарушено ODR! Даже ослабленное. Это снимает ответственность за последствия с авторов транслятора!
Да, так получилось, я его явно нарушил. Вот если бы еще все остальные случаи были б такими же явными. И с __COUNTER__ можно намудрить, как раз из-за независимости подсчёта в разных TU.
GN>>Про const static соглашусь. В остальных случаях баг может пролезть в результат. E>Нет. Не const тоже. Вообще-то если статическое поле имеет нетривиальные конструктор или деструктор, то пофиг const оно или не сonst...
Опс мне следовало написать "static const интегральные типы и enum" Это при том что я вообще всё люблю писать в заголовках и не люблю много TU. Но вот под определение такого статика отдельной TU не жалко, если надо. До сих пор думаю что это такая багофича MSVC.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[14]: Чем статические данные отличаются от методов?
Здравствуйте, gear nuke, Вы писали:
GN>Опс мне следовало написать "static const интегральные типы и enum" Это при том что я вообще всё люблю писать в заголовках и не люблю много TU. Но вот под определение такого статика отдельной TU не жалко, если надо. До сих пор думаю что это такая багофича MSVC.
Вроде бы везде можно определять шаблоны статических членов...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
А>Так как быть с шаблонными классами и статическими элементами??
template<typename T> class counter
{
static T cnt;
public:
counter() { cnt++; }
~counter() { cnt--; }
};
template<typename T> T counter<T>::cnt = T();
Может быть так?
Всё зависит от того что нужно автору, если ему нужно считать количество созданных классов определенного типа (class A : counter<A>), то стоит воспользоваться int, как отписали выше.
gear nuke:
GN>Здравствуйте, Andrew S, Вы писали:
AS>>А что, есть сомнения?
GN>Да, есть. Не могу найти, где это разрешено в Стандарте.
3.2/5: "There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements [...]" — дальше идёт описание требований к идентичности определений.
GN>непонятно, почему инстанциация
template<> int counter<int>::cnt;
GN>ведёт себя отлично от 9.4.2/5 (There shall be exactly one definition of a static data member that is used in a program; no diagnostic is required; see 3.2.).
Это объявление, не являющееся определением (см. 14.7.3/15).
Здравствуйте, Николай Ивченков, Вы писали:
НИ> — дальше идёт описание требований к идентичности определений.
Вот это важная деталь. Другими словами Стандарт разрешает, но на свой страх и риск.
GN>>непонятно, почему инстанциация НИ>
НИ>template<> int counter<int>::cnt;
НИ>
GN>>ведёт себя отлично от 9.4.2/5 (There shall be exactly one definition of a static data member that is used in a program; no diagnostic is required; see 3.2.).
НИ>Это объявление, не являющееся определением (см. 14.7.3/15).
Это моя ошибка, следовало не вырывать из контекста и писать так
// 1.cpptemplate<> int counter<int>::cnt = 1;
// 2.cpptemplate<> int counter<int>::cnt = -1;
и предложенная замена — суть одни и те же подводные камни.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[15]: Чем статические данные отличаются от методов?
Здравствуйте, Erop, Вы писали:
E>Вроде бы везде можно определять шаблоны статических членов...
May и can по-нашему оба значат "можно". Про что в Стандарте написано "may", в проектные требования может пойти как "can, but... shall not"
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
gear nuke:
GN>Другими словами Стандарт разрешает, но на свой страх и риск.
Я не понял твою мысль. Что именно он, по-твоему, разрешает?
GN>
// 1.cpp
GN>template<> int counter<int>::cnt = 1;
GN>// 2.cpp
GN>template<> int counter<int>::cnt = -1;
GN>
GN>что я и пробовал (успешно) собрать.
Здесь имеет место undefined behavior. Реализация не обязана диагностировать данное нарушение ODR.
GN>Мой поинт в том, что Re: Static variables & templates
и предложенная замена — суть одни и те же подводные камни.
НИ>Я снова не понял твою мысль. Что не так в примере по этой ссылке
Этот вопрос меня тоже интересует, о чем я и спрашивал поставивших минусу
НИ> и что за "предложенная замена" имеется в виду?
Предложено было заменить функцию-член данными.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth