我有一个头文件,它声明了一个带有静态变量的模板并定义了它:
/* 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
)时,符号 forfoo<123>::bar
存在并声明为弱。但是,在 my 中,符号 forfoo<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:我怎么能预测我观察到的行为?也就是说,究竟是什么让编译器声明符号为弱?