在.h文件中定义的模板类静态成员变量应该发生什么?
What should happen to template class static member variables with definition in the .h file
如果模板类定义包含依赖于模板类型的静态成员变量,我不确定可靠的行为应该是什么?
在我的例子中,最好将该静态成员的定义与类定义放在同一个.h文件中,因为
- 我希望类是通用的许多模板数据类型,我目前没有知道。
- 我只想要共享静态成员的一个实例在我的程序中为每个给定的模板类型。(一个用于所有
MyClass<int>
,一个用于所有MyClass<double>
,等等)
我可以最简短地说,这个链接中列出的代码在使用gcc 4.3编译时的行为完全符合我的要求。这种行为是否符合c++标准,以便我在使用其他编译器时可以依赖它?
那个链接不是我的代码,而是CodeMedic在这里讨论的一个反例。我发现了其他一些类似的辩论,但我认为没有一个是决定性的。
我认为链接器正在巩固发现的多个定义(在示例a.o
和b.o
中)。这是必需的/可靠的链接器行为吗?
From N3290, 14.6:
通常,将静态成员定义与模板类定义一起放在头文件中:[…类模板的静态数据成员定义在每个被隐式实例化的翻译单元[…]],除非相应的专门化被显式实例化[…]] .
template <typename T>
class Foo
{
static int n; // declaration
};
template <typename T> int Foo<T>::n; // definition
如果你打算在你的代码中使用显式实例化,比如:
template <> int Foo<int>::n = 12;
那么,如果Foo<int>
也在包含显式实例化的tu之外的其他tu中使用,则必须不将模板化的定义放在头文件中,因为这样会得到多个定义。
但是,如果您确实需要为所有可能的参数设置初始值而不使用显式实例化,则必须将其放在头文件中,例如TMP:
// in the header
template <typename T> int Foo<T>::n = GetInitialValue<T>::value; // definition + initialization
这完全是对@Kerrek SB出色答案的补充。我想把它作为评论添加,但是已经有很多评论了,所以默认情况下新的评论是隐藏的。
所以,他的例子和我看到的其他例子都是"简单的",因为静态成员变量的类型是事先已知的。这很容易,因为例如编译器知道任何模板实例化的存储大小,所以有人可能会认为编译器可以使用时髦的mangling方案,输出一次变量定义,并将其余部分卸载给链接器,这甚至可能工作。
但是令人惊讶的是,当静态成员类型依赖于模板形参时,它可以工作。例如:
template <typename width = uint32_t>
class Ticks : public ITimer< width, Ticks<width> >
{
protected:
volatile static width ticks;
}
template <typename width> volatile width Ticks<width>::ticks;
(注意,静态变量的显式实例化不需要(或允许)默认的width规格)。
因此,它带来了更多的想法,c++编译器必须做相当多的处理-特别是,为了实例化模板,不仅需要模板本身,而且还必须收集所有的[static member]显式实例化(人们可能只会奇怪为什么它们是单独的语法结构,而不是在模板类中详细说明)。
对于链接器级别的实现,对于GNU binutils它的"通用符号":http://sourceware.org/binutils/docs/as/Comm.html通讯。(对于微软工具链,它被命名为COMDAT,正如另一个答案所说)。
链接器对这种情况的处理几乎与应用了__declspec(selectany)声明的非模板类静态成员完全相同,如下所示:
class X {
public:
X(int i){};
};
__declspec(selectany) X x(1);//works in msvc, for gcc use __attribute__((weak))
正如msdn所说:"在链接时,如果看到COMDAT的多个定义,链接器会选择一个并丢弃其余的…对于动态初始化的全局对象,selectany也会丢弃未引用对象的初始化代码。"
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 未初始化的变量有什么危险
- 在C/C++中将变量名定义为__00000001有什么好处吗
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- Visual C++: MSVC vs. GCC+CLANG: 处理 lambda 捕获类成员变量,正确的方法是什么?
- 存储变量的更有效方法是什么?
- 变量 BitMask 在函数 CeilLog2 中的实际效果是什么?
- 这个变量在 C++ 中的范围是什么?
- 从二进制流中读取时,将双精度变量的地址转换为 char* 意味着什么?
- 变量按什么顺序相乘
- 与普通变量相比,仅仅读取原子变量的性能有什么不同吗
- 使用 gtest 框架在单元测试代码中检查目标对象的私有变量的最佳实践是什么?
- C++在变量的内存地址上做什么来"deallocate"它?
- 有什么方法可以使用 int 变量来完成组件名称吗?
- 从"LLONG_MAX 秒"构造 std::chrono::毫秒变量时发生了什么?
- 将共享指针传递给函数参数 - 将其分配给局部变量的正确方法是什么
- 正在连接的等待条件变量的线程会发生什么情况?
- 当使用Lua作为嵌入式语言(比如c++)时,有什么简单/方便的方法可以找到变量在Lua中的定义位置吗
- 什么是变量均值'int border = borderType & ~BORDER_ISOLATED'?