Обработайте статическую переменную по шаблону

Я полностью соглашаюсь с Sklivvz. Но для существующих проектов, можно очистить категорию нарушений FxCop по категориям.

Время от времени, Жандарм принимает новые правила, которые довольно полезны. Таким образом, можно использовать Жандарма, кроме того.

59
задан Jarod42 27 April 2015 в 07:56
поделиться

1 ответ

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

template<typename T>
struct F {
  static int const value;
};

template<typename T>
int const F<T>::value = sizeof(T);

Неизвестно, что такое T - Стандарт говорит, что определение вне шаблона класса является определение шаблона, в котором параметры наследуются от своего владельца шаблона класса.


Я провел небольшой эксперимент с GCC. Далее у нас есть один неявный экземпляр F :: value , и одна явная специализация F :: value , которая должна быть определена в файле .cpp, чтобы не вызывать ошибок дублирования символов при многократном включении.

// Translation Unit 1
template<typename T>
struct F {
  static int value; 
};

template<typename T>
int F<T>::value = sizeof(T);

// this would belong into a .cpp file
template<> int F<char>::value = 2;

// this implicitly instantiates F<float>::value
int test = F<float>::value;

int main() { }

Вторая единица трансляции содержит просто еще одно неявное создание одного и того же статического элемента данных.

template<typename T>
struct F {
  static int value; 
};

template<typename T>
int F<T>::value = sizeof(T);

int test1 = F<float>::value;

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

objdump -Ct main1.o # =>
# cut down to the important ones
00000000 l    df *ABS*  00000000 main1.cpp
0000000a l     F .text  0000001e __static_initialization_and_destruction_0(int, int)
00000000 l    d  .data._ZN1FIfE5valueE  00000000 .data._ZN1FIfE5valueE
00000028 l     F .text  0000001c global constructors keyed to _ZN1FIcE5valueE
00000000 g     O .data  00000004 F<char>::value
00000000 g     O .bss   00000004 test
00000000 g     F .text  0000000a main
00000000  w    O .data._ZN1FIfE5valueE  00000004 F<float>::value

Итак, как мы видим, F :: value является слабым символом, который означает, что компоновщик можно увидеть несколько из них во время ссылки. test , main и F :: значение - глобальные (неслабые) символы. Связывая main1.o и main2.o вместе, мы видим в выводе карты ( -Wl, -M ) следующее

# (mangled name)
.data._ZN1FIfE5valueE
    0x080497ac        0x4 main1.o                                             
    0x080497ac                F<float>::value

Это означает, что на самом деле он отбрасывает все, кроме одного экземпляра.

63
ответ дан 24 November 2019 в 18:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: