初始化模板类中嵌套类的静态实例

The initialization of a static instance of a nested class in template class

本文关键字:静态 实例 嵌套 初始化      更新时间:2023-10-16

我想这样做:

template <typename T>
class S
{
    ...
    class A
    {
        ~A(){cout << "~A";}
    };
    static A obj;
};
template <typename T>
typename S<T>::A S<T>::obj;
int main()
{...}

但是当程序启动时,不会创建嵌套类A的静态实例。"~A"则不会打印。问题出在哪里?

答案取决于"…"中写的内容部分问题。下面是一个使用gcc 4.8.1工作的完整示例;即打印"Ahello~A"如果您注释掉main()中的代码,则程序不会产生任何结果。

#include <iostream>
using namespace std;
template <typename T>
class S
{
public:
    T m;
    class A
    {
    public:
        A() {cout << "A";}
        void say() {cout << "hello";}
        ~A(){cout << "~A";}
    };
    static A obj;
};
template <typename T>
typename S<T>::A S<T>::obj;
int main() {
    S<int>::obj.say();
}

如果您在代码中不使用static,但仍然希望创建静态实例,则jxh给出的答案适用。在这种(不太可能的)情况下,您必须显式实例化模板类:template class S<int>;

模板中的静态对象未使用

当您隐式实例化模板类时,只有所使用的类的部分才会被实例化。该标准特别提到了C++中的静态数据成员。11§14.7.1&第;8:

类模板的隐式实例化不会导致该类的任何静态数据成员被隐式实例化。

解决方案

您将需要以某种方式引用静态对象的非模板代码,或者需要显式实例化模板。

参考静止物体

由于obj是静态的,并且对S是私有的,因此在S中需要一些引用此对象的公共代码。例如,返回它的静态方法。

tempalte <typename T>
class S
{
    //... define class A
    static A obj;
public:
    static A & get_obj () { return obj; }
};
template <typename T>
typename S<T>::A S<T>::obj;

然后,您可以从main()调用此方法来隐式实例化obj

int main()
{
    get_obj();
}

显式实例化模板

模板类的显式实例化将完全定义它,就好像该模板类是作为常规类编写的一样。因此,将创建静态对象,而无需隐式引用它。

template class S<int>;

关于Singleton模式

隐式实例化行为减少膨胀

如果您使用的是单例代码,那么您观察到的行为实际上就是您想要的。您只希望在实际使用的情况下创建您的singleton对象。这将防止未使用的代码不必要地占用程序中的资源。

防止显式实例化的膨胀

由于希望防止程序的运行时膨胀,因此即使Singleton被显式实例化,也希望这样做。这自然是通过在返回它的方法内部对单例实例进行范围界定来实现的

template <typename T>
class S
{
    class A
    {
        friend S;
        ~A(){std::cout << "~An";}
        static A & getInstance () {
            static A obj;
            return obj;
        }
    };
public:
    void foo () { A::getInstance(); }
};

当静态实例的作用域在返回它的静态方法内时,不需要在类之外创建它的模板定义。静态实例仅在调用getInstance()时创建。