Static variables & templates
От: Аноним  
Дата: 20.10.09 20:24
Оценка:
Занятная штука:
template<typename T>
class counter{
    static T cnt;
public:
    counter(){
        cnt++;
    }

    ~counter(){
        cnt--;
    }
};

template<typename T>
int counter<T>::cnt = 0;

В функции main:
counter<int> i;
counter<int> j;

counter<float> f; //Понятно, ошибка C2371: 'cnt' : redefinition; different basic types


Так как быть с шаблонными классами и статическими элементами??
добавлена разметка — Кодт
Re: Static variables & templates
От: Andrew S Россия http://alchemy-lab.com
Дата: 20.10.09 21:26
Оценка: +1
А>template<typename T>
А>int counter<T>::cnt = 0;

А>В функции main:

А>counter<int> i;
А>counter<int> j;

А>counter<float> f; //Понятно, ошибка C2371: 'cnt' : redefinition; different basic types



А>Так как быть с шаблонными классами и статическими элементами??


T counter<T>::cnt = T();
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: Static variables & templates
От: zaufi Земля  
Дата: 20.10.09 21:30
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Занятная штука:


А>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... в таком случае все работает...
Re[2]: Static variables & templates
От: zaufi Земля  
Дата: 20.10.09 21:32
Оценка:
Здравствуйте, 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 все также буит работать...
Re[2]: Static variables & templates
От: Caracrist https://1pwd.org/
Дата: 20.10.09 21:43
Оценка: +1
Здравствуйте, Andrew S, Вы писали:

А>>template<typename T>

А>>int counter<T>::cnt = 0;

А>>В функции main:

А>>counter<int> i;
А>>counter<int> j;

А>>counter<float> f; //Понятно, ошибка C2371: 'cnt' : redefinition; different basic types



А>>Так как быть с шаблонными классами и статическими элементами??


AS>T counter<T>::cnt = T();

скорее
static int cnt;
~~~~~
~lol~~
~~~ Single Password Solution
Re: Static variables & templates
От: ffk  
Дата: 21.10.09 03:45
Оценка: -3
Здравствуйте, Аноним, Вы писали:

А>Занятная штука:


А>template<typename T>

А>class counter{
А> //static T cnt;
А>public:
А> counter(){
А> cnt()++;
А> }

А> ~counter(){

А> cnt()--;
А> }
A>private:
A> int& cnt() {static int cnt_ = 0; return cnt;}
А>};
Re[2]: Static variables & templates
От: Caracrist https://1pwd.org/
Дата: 21.10.09 06:45
Оценка:
Здравствуйте, 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>
А>};

это плохо без особой нужды использовать статические в функции. Это всё равно что добавить if (true) который никогда не вырежит компилятор. И должно быть оправдание для такого действия.
~~~~~
~lol~~
~~~ Single Password Solution
Re[3]: Static variables & templates
От: ffk  
Дата: 21.10.09 07:36
Оценка:
Здравствуйте, 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% это пофиг, даже не заметешь.
Критикуешь, предложи более красивое решение.
Re[4]: Static variables & templates
От: Caracrist https://1pwd.org/
Дата: 21.10.09 07:53
Оценка: +1
Здравствуйте, ffk, Вы писали:

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


ffk>В 99.99% это пофиг, даже не заметешь.

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

уже предложил:
http://www.rsdn.ru/forum/cpp/3576649.1.aspx
Автор: Caracrist
Дата: 21.10.09


в целом оно выглядит вот так:
template<typename T>
class counter{
static int cnt;
public:
counter(){
cnt++;
}

~counter(){
cnt--;
}
// тут гдето должны быть публичные функции или friends иначе этот счётчик никогда никто не прочтёт
};

template<typename T>
int counter<T>::cnt = 0;


простота залог успеха
~~~~~
~lol~~
~~~ Single Password Solution
Re: Static variables & templates
От: dcb-BanDos Россия  
Дата: 21.10.09 08:46
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Так как быть с шаблонными классами и статическими элементами??


что-то я не понял, есть желание использовать для счетчика вместо int скажем std::complex?
если нет, то и используй int в шаблоне(static int count
Ничто не ограничивает полет мысли программиста так, как компилятор.
Re[5]: Static variables & templates
От: ffk  
Дата: 21.10.09 09:30
Оценка:
Здравствуйте, Caracrist, Вы писали:

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


C>template<typename T>

C>int counter<T>::cnt = 0;
C>[/ccode]

C>простота залог успеха


Мда,.. не знал что темплейтные статические мемберы можно прямо в хидере инстнционировать.
Re[3]: Static variables & templates
От: Andrew S Россия http://alchemy-lab.com
Дата: 21.10.09 18:17
Оценка:
А>>>template<typename T>
А>>>int counter<T>::cnt = 0;

А>>>В функции main:

А>>>counter<int> i;
А>>>counter<int> j;

А>>>counter<float> f; //Понятно, ошибка C2371: 'cnt' : redefinition; different basic types



А>>>Так как быть с шаблонными классами и статическими элементами??


AS>>T counter<T>::cnt = T();

C>скорее
C>static int cnt;

смотря какую семантику имеет counter. Из исходного сообщения она не очевидна.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[5]: Static variables & templates
От: gear nuke  
Дата: 21.10.09 20:00
Оценка: :)
Здравствуйте, 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
Re[6]: Static variables & templates
От: Andrew S Россия http://alchemy-lab.com
Дата: 21.10.09 20:32
Оценка: +1
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>>простота залог успеха


GN>Насколько успешно такой хидер может быть включён в несколько единиц трансляции? Без использования __declspec(selectany)


А что, есть сомнения?
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[7]: Static variables & templates
От: gear nuke  
Дата: 21.10.09 21:51
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>А что, есть сомнения?


Да, есть. Не могу найти, где это разрешено в Стандарте.

Изменю немного пример

// t.hpp
template<typename T>
struct counter{
  static int cnt;
};

// t.cpp
#include "t.hpp"

template<typename T>
int counter<T>::cnt = -1;

void* f();
int main()
{
  counter <int> c;
  void* volatile p = &c.cnt;
  p = f();
}

// t2.cpp
#include "t.hpp"

template<typename T>
int counter<T>::cnt = 1;

void* f()
{
  counter <int> c;
  void* volatile p = &c.cnt;
  return p;
}

Собираем так:
cl /FAs t.cpp t2.cpp

PUBLIC    ?cnt@?$counter@H@@2HA                ; counter<int>::cnt
PUBLIC    _main
EXTRN    ?f@@YAPAXXZ:PROC                ; f
;    COMDAT ?cnt@?$counter@H@@2HA
; File t.cpp
_DATA    SEGMENT
?cnt@?$counter@H@@2HA DD 0ffffffffH            ; counter<int>::cnt
; Function compile flags: /Odtp
_DATA    ENDS
_TEXT    SEGMENT
_p$ = -4                        ; size = 4
_main    PROC

; 8    : {

    push    ebp
    mov    ebp, esp
    sub    esp, 8

; 9    :   counter <int> c;
; 10   :   void* volatile p = &c.cnt;

    mov    DWORD PTR _p$[ebp], OFFSET ?cnt@?$counter@H@@2HA ; counter<int>::cnt

; 11   :   p = f();

    call    ?f@@YAPAXXZ                ; f
    mov    DWORD PTR _p$[ebp], eax

; 12   : }

    xor    eax, eax
    mov    esp, ebp
    pop    ebp
    ret    0
_main    ENDP
_TEXT    ENDS
END

PUBLIC    ?cnt@?$counter@H@@2HA                ; counter<int>::cnt
PUBLIC    ?f@@YAPAXXZ                    ; f
;    COMDAT ?cnt@?$counter@H@@2HA
; File t2.cpp
_DATA    SEGMENT
?cnt@?$counter@H@@2HA DD 01H                ; counter<int>::cnt
; Function compile flags: /Odtp
_DATA    ENDS
_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
_TEXT    ENDS
END

Намеренно опущу изучение слинкованного бинарника.

2й вариант сборки:
cl /GL /FAs t.cpp t2.cpp

PUBLIC    ?cnt@?$counter@H@@2HA                ; counter<int>::cnt
EXTRN    @__security_check_cookie@4:PROC
;    COMDAT ?cnt@?$counter@H@@2HA
_DATA    SEGMENT
?cnt@?$counter@H@@2HA DD 0ffffffffH            ; counter<int>::cnt
PUBLIC    _main
; Function compile flags: /Odtp
; File t.cpp
_TEXT    SEGMENT
_p$ = -4                        ; size = 4
_main    PROC

; 8    : {

    push    ebp
    mov    ebp, esp
    sub    esp, 8

; 9    :   counter <int> c;
; 10   :   void* volatile p = &c.cnt;

    mov    DWORD PTR _p$[ebp], OFFSET ?cnt@?$counter@H@@2HA ; counter<int>::cnt

; 11   :   p = f();

    call    ?f@@YAPAXXZ                ; f
    mov    DWORD PTR _p$[ebp], eax

; 12   : }

    xor    eax, eax
    mov    esp, ebp
    pop    ebp
    ret    0
_main    ENDP
_TEXT    ENDS
END

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]: Чем статические данные отличаются от методов?
От: Erop Россия  
Дата: 22.10.09 09:19
Оценка:
Здравствуйте, gear nuke, Вы писали:

GN>Здравствуйте, Andrew S, Вы писали:


AS>>А что, есть сомнения?


GN>Да, есть. Не могу найти, где это разрешено в Стандарте.


В принципе, есть похожие объекты -- это шаблоны функций и методов. Где, например, написано про них?

GN>
// t.hpp
GN>template<typename T>
GN>int counter<T>::cnt = -1;
GN>template<typename T>
GN>int counter<T>::cnt = 1;
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]: Чем статические данные отличаются от методов?
От: gear nuke  
Дата: 22.10.09 11:03
Оценка:
Здравствуйте, Erop, Вы писали:

E>В принципе, есть похожие объекты -- это шаблоны функций и методов. Где, например, написано про них?


Можно иметь 2 копии одной функции и вызывать их из разных мест — наблюдаемое поведение не изменится. Если имеется 2 копии одного объекта, то это подразумевает возможность хранения разных состояний, что и демонстрирует мой пример.

GN>>
// t.hpp
GN>>template<typename T>
GN>>int counter<T>::cnt = -1;
GN>>template<typename T>
GN>>int counter<T>::cnt = 1;
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]: Чем статические данные отличаются от методов?
От: Erop Россия  
Дата: 22.10.09 11:30
Оценка: +1
Здравствуйте, 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]: Чем статические данные отличаются от методов?
От: Caracrist https://1pwd.org/
Дата: 22.10.09 11:31
Оценка: +1
Здравствуйте, gear nuke, Вы писали:

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


E>>В принципе, есть похожие объекты -- это шаблоны функций и методов. Где, например, написано про них?


GN>Можно иметь 2 копии одной функции и вызывать их из разных мест — наблюдаемое поведение не изменится.


template<typename T>

struct S
{
void myFunc()
{
static int oproverzhenie;
// blablabla
}
};
~~~~~
~lol~~
~~~ Single Password Solution
Re[11]: Чем статические данные отличаются от методов?
От: gear nuke  
Дата: 22.10.09 14:34
Оценка:
Здравствуйте, 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
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.