模板类的静态成员变量的隐式初始化 [英] Implicit initialization of static member variables for template classes

查看:179
本文介绍了模板类的静态成员变量的隐式初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前,我正在一个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.

这篇关于模板类的静态成员变量的隐式初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆