首页  >  文章  >  后端开发  >  为什么“B::getB()”无法在具有静态成员的模板类中初始化“mB”?

为什么“B::getB()”无法在具有静态成员的模板类中初始化“mB”?

Linda Hamilton
Linda Hamilton原创
2024-10-31 05:59:02454浏览

 Why Does `B::getB()` Fail to Initialize `mB` in Templated Classes with Static Members?

模板中的静态成员初始化:深入研究

在 C 中,嵌套辅助结构的静态成员初始化通常对于非模板化类来说不会出现问题。但是,当封闭类被模板化时,如果在主代码中未访问辅助对象,则会出现潜在的怪癖。

模板化类的问题

考虑以下简化示例:

<code class="cpp">struct A
{
    struct InitHelper
    {
        InitHelper()
        {
            A::mA = "Hello, I'm A.";
        }
    };
    static std::string mA;
    static InitHelper mInit;

    static const std::string& getA(){ return mA; }
};

template<class T>
struct B
{
    struct InitHelper
    {
        InitHelper()
        {
            B<T>::mB = "Hello, I'm B.";
        }
    };
    static std::string mB;
    static InitHelper mInit;

    static const std::string& getB() { return mB; }
    static InitHelper& getHelper(){ return mInit; }
};</code>

这里,嵌套的 InitHelper 初始化 A 的静态成员 mA 和 B 的 mB。

当我们尝试初始化模板类 B 中的成员时,就会出现问题。使用 getB 方法如下所示,不会触发 mB 的初始化:

<code class="cpp">std::cout << "B = " << B<int>::getB() << std::endl;</code>

发生这种情况是因为,根据 ISO/IEC C 2003 标准 (14.7.1),仅发生静态数据成员的初始化当成员本身以需要其定义的方式使用时。在这种情况下,由于 mB 仅在模板类的 getB() 方法中引用,因此编译器不会隐式实例化其定义。

隐式实例化和显式特殊化

要了解编译器的行为,澄清隐式实例化的概念很重要。对于模板中的静态数据成员,隐式实例化会实例化声明,但不会实例化定义。仅当静态数据成员以需要其定义(例如赋值)的方式使用时,实际的初始化(构造函数调用)才会发生。

另一方面,显式专业化在命名空间或类中使用显式声明,其中已命令初始化。换句话说,专用的静态数据成员始终在其类模板的任何实例化之前初始化。

答案

在您的特定代码示例中,调用 B::getHelper()触发 mB 和 mInit 的初始化,因为 getHelper 返回 mInit 的引用,这需要 InitHelper 存在。

但是,依赖初始化的顺序是未定义的行为。正确的解决方案是显式特化类 B 中的静态数据成员 mInit。这将确保始终创建辅助对象,并且 B 的任何后续实例化都将正确初始化其静态数据成员。

结论

总而言之,C 模板中的静态成员初始化需要仔细考虑。隐式实例化仅实例化声明,而不实例化定义。为了有序且可靠的初始化,在处理包含静态数据成员的模板化类时应考虑显式专业化。

以上是为什么“B::getB()”无法在具有静态成员的模板类中初始化“mB”?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn