【发布时间】:2020-04-15 14:04:38
【问题描述】:
下面的代码,有2个模板静态字段成员的定义,每个定义定义template1<int>::x具有不同的值。
人们会期望链接器拒绝此类重新定义,因为它们具有不同的值。
但是 g++ 和 MSVC 的编译和链接传递,以及使用哪个定义取决于源传递给链接器的顺序。
此行为是否符合 C++ 标准、未定义行为或链接器错误?
my_template.h
template <class T>
class template1
{
public:
static int x;
};
Src2.cpp
#include <stdio.h>
#include "my_template.h"
template <class T>
int template1<T>::x = 2;
void my_func() // definition
{
printf("my_func: template1<int>::x = %d\n", template1<int>::x); // definition of X to 2.
printf("my_func: template1<char>::x = %d\n", template1<char>::x); // definition of X to 2.
}
Main.cpp
#include <cstdio>
#include "my_template.h"
template <class T>
int template1<T>::x = 1;
void my_func();
int main()
{
printf("main: template1<int>::x = %d\n", template1<int>::x); // definition of X to 1.
my_func();
return 0;
}
使用 g++ (MinGW.org GCC Build-20200227-1) 9.2.0+ 编译
编译1
g++ -o prog Src2.cpp Main.cpp
输出1
main: template1<int>::x = 2
my_func: template1<int>::x = 2
my_func: template1<char>::x = 2
编译2
g++ -o prog Main.cpp Src2.cpp
输出2
main: template1<int>::x = 1
my_func: template1<int>::x = 1
my_func: template1<char>::x = 2
也观察到
Microsoft (R) C/C++ Optimizing Compiler Version 19.25.28612 for x86
当我反汇编带有-S标志的代码时,每个编译单元都定义了相同的符号名称。
与Nightra合作。
【问题讨论】:
-
FWIW,如果你有 C++17,你可以在类中使用
static inline int x = 2;,甚至不必担心在类外定义成员。在 C++17 之前,由于定义是一个模板,您可以将其移动到类之后的头文件中,因为所有模板都是隐式内联的。