模板类的静态成员变量的隐式初始化
当前,我正在一个C ++项目中,我计划在其中嵌入Lua脚本.出于这个原因,某些类需要导出到Lua,而我想使其更加方便,因此我创建了一个模板类:
Currently I am working on a C++ project in which I plan to embed Lua scripts. For that reason certain classes need to be exported to Lua and I wanted to make this more convenient therefore I created a template class:
template <class T>
class ExportToLua {
public:
ExportToLua() {}
~ExportToLua() {}
private:
static int m_registered;
};
template <class T> int ExportToLua<T>::m_registered = T::exportToLua();
现在,每个需要导出的类都从ExportToLua<T>
派生,其中T
=要导出的类".示例:
Now every class that needs to be exported is derived from ExportToLua<T>
with T
="the class to be exported". Example:
class Example: public ExportToLua<Example> {
public:
Example();
virtual ~Example();
static int exportToLua();
private:
};
其中,Example
的静态成员函数exportToLua()
保存特定于类的注册代码.我的理解是,每个编译单元(即每个T
)都存在一个静态成员变量ExportToLua<T>::m_registered
的实例.
where Example
's static member function exportToLua()
holds the class-specific registration code. My understanding is that an instance of the static member variable ExportToLua<T>::m_registered
exists for every compile unit - that is - for every T
.
但是,当我启动程序时,注册码永远不会被调用.例如example.cpp:
But when I start my program the registration code never gets called. For example in example.cpp:
int Example::exportToLua() {
std::cout << "int Example::exportToLua()" << std::endl;
return -2;
}
但是,我在运行程序时从未看到此消息.
however I never see this message when I run my program.
知道为什么吗?编译器是否在优化"了静态变量m_registered
,因为我没有在任何地方使用它?
Any idea why? Is the compiler some "optimizing away" the static variable m_registered
, because I am not using it anywhere?
感谢您的输入,
最好, 克里斯多夫(Christoph)
Best, Christoph
您已经在标准中找到了行为本身的原因.因此,作为一种解决方法,您可以通过从模板构造函数或析构函数中引用静态成员来欺骗"编译器以实例化该静态成员.
You already found the reason in the standard why the behavior is the way it is. So as a workaround, you can 'trick' the compiler into instantiating that static member by referencing it from either the template constructor or destructor.
#define FORCE_INSTANTIATE(x) (x)
// or (avoids -Wall and -pedantic warnings)
// template <typename T> inline void FORCE_INSTANTIATE(T) {}
template <class T>
class ExportToLua
{
public:
ExportToLua() {}
virtual ~ExportToLua() { FORCE_INSTANTIATE(m_registered); }
private:
static int m_registered;
};
它似乎可以在 此演示 中使用.
It seems to work in this demo.
编辑:正如DyP正确指出的那样,一个定义规则在这里起作用,而无论是否实例化ExportToLua<T>::m_registered
.
As DyP correctly pointed out, the One-Defintion-Rule comes into play here in whether ExportToLua<T>::m_registered
gets instantiated or not.
为保证隐式实例化,请确保您至少满足以下条件之一:
To guarantee implicit instantiation, make sure you meet at least one of the following conditions:
- 为要导出的类的构造函数或析构函数提供定义.
- 您创建该类的实例,该实例在代码其他部分的其他地方使用.如果您未提供默认的ctor,则会强制编译器提供默认的ctor,从而触发必要的模板实例化.
如果出于任何原因都不能满足这些条件,则需要从模板中显式实例化所需的成员.例如,
If none of those conditions can be met for whatever reason then you'll need to explicitly instantiate the members you want from the template. For example,
class Example: public ExportToLua<Example>
{
public:
// ...
static int exportToLua();
// etc.
};
template int ExportToLua<Example>::m_registered;
如果需要,您可以将其包装到宏中以使其更易于使用.
You can wrap that into a macro to make it nicer to use if desired.