У меня есть заголовочный файл, который объявляет шаблон со статической переменной, а также определяет его:
/* my_header.hpp */
#ifndef MY_HEADER_HPP_
#define MY_HEADER_HPP_
#include <cstdio>
template<int n>
struct foo {
static int bar;
static void dump() { printf("%d\n", bar); }
};
template<int n>
int foo<n>::bar;
#endif // MY_HEADER_HPP_
Этот заголовок включен как main.cpp
, так и общей библиотекой mylib
. В частности, mylib_baz.hpp
просто включает этот шаблон и объявляет функцию, которая изменяет специализацию шаблона.
/* mylib_baz.hpp */
#ifndef MYLIB_BAZ_HPP_
#define MYLIB_BAZ_HPP_
#include "my_header.hpp"
typedef foo<123> mylib_foo;
void init_mylib_foo();
#endif // MYLIB_BAZ_HPP_
а также
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
Когда я создаю mylib.so
(содержащий mylib_baz.o
), символ foo<123>::bar
присутствует и объявляется слабым. Однако символ для foo<123>::bar
объявлен слабым и в моем main.o
:
/* main.cpp */
#include "my_header.hpp"
#include "mylib_baz.hpp"
int main() {
foo<123>::bar = 456;
foo<123>::dump(); /* outputs 456 */
init_mylib_foo(); /* outputs 123 */
foo<123>::dump(); /* outputs 123 -- is this guaranteed? */
}
Похоже, я нарушаю одно правило определения (foo<123>::bar
определено как в my_header.cpp
, так и в main.cpp
). Однако и в g++, и в clang символы объявляются слабыми (или уникальными), так что меня это не укусит — все обращения к foo<123>::bar
изменяют один и тот же объект.
Вопрос 1: Является ли это совпадением (может быть, ODR работает по-разному для статических членов шаблонов?) или мне действительно гарантируется такое поведение стандартом?
Вопрос 2. Как я мог предсказать наблюдаемое поведение? То есть что именно заставляет компилятор объявлять символ слабым?
extern
для совместного использования переменных между исходными файлами в C? — эта функция на самом деле является свойством компоновщика, и есть неплохая вероятность того, что ваши C и C++ компиляторы используют технологию компоновщика.) - person Jonathan Leffler   schedule 18.09.2015bar
extern
и определить его только вmylib_baz.cpp
, решив эту проблему. Но мне действительно любопытно копнуть глубже и увидеть причину поведения, которое я наблюдаю. - person FreenodeForsakeMe   schedule 18.09.2015foo<123>::bar
определены как в my_header.cpp, так и в main.cpp... Что? Я вижу, что это определено в одном месте, которое не является ни одним из упомянутых вами:my_header.hpp
. Это одно определение. - person Barry   schedule 18.09.2015mylib_baz.hpp
), которые затем компилируются отдельно. В итоге перед линковкой в обоих .o файлах есть определение - person Maksim Solovjov   schedule 18.09.2015