【问题标题】:Initializing static pointer in templated class在模板类中初始化静态指针
【发布时间】:2010-08-04 18:15:21
【问题描述】:

考虑这样一个类:

template < class T >
class MyClass
{
  private:
    static T staticObject;
    static T * staticPointerObject;
};
...
template < class T >
T MyClass<T>::staticObject; // <-- works
...
template < class T >
T * MyClass<T>::staticPointerObject = NULL; // <-- cannot find symbol staticPointerObject.

我无法弄清楚为什么我无法成功创建该指针对象。

上面的代码都是在header中指定的,我提到的问题是链接步骤出错,所以没有找到具体的符号。

【问题讨论】:

    标签: c++ templates static-members


    【解决方案1】:

    “找不到符号 staticPointerObject” - 这看起来像 链接器 错误消息。是吗? (这样的细节必须在您的问题中指定)。

    如果是,它们很可能会发生,因为您将静态成员的定义放入 实现 文件(.cpp 文件)中。为了使其正常工作,应将定义放入头文件(.h 文件)中。

    同样,必须在您的问题中指定此类详细信息。没有它们,它就会变成一场随机的猜测盛宴。

    【讨论】:

      【解决方案2】:

      我怀疑您的第一个示例的原因如下(来自 2003 C++ std 文档)。特别注意最后一句话——从你的例子来看,似乎没有什么“需要成员定义存在”。

      14.7.1 隐式实例化 [temp.inst] 1 除非类模板特化已显式实例化 (14.7.2) 或显式实例化 特化(14.7.3),类模板特化是隐式的 当特化在上下文中被引用时被实例化 需要完全定义的对象类型或当 类类型影响程序的语义。隐含的 类模板特化的实例化导致隐式 声明的实例化,但不是定义的实例化或 类成员函数、成员类的默认参数, 静态数据成员和成员模板;它会导致隐式 成员匿名联合定义的实例化。除非一个 类模板或成员模板的成员已显式 实例化或显式特化, 成员在特化时被隐式实例化 在需要成员定义存在的上下文中引用; 特别是,初始化(以及任何相关的副作用) 静态数据成员不会出现,除非该静态数据成员是 本身以需要定义静态数据的方式使用 成员存在。

      【讨论】:

        【解决方案3】:

        您对静态成员的第一个“定义”只是一个声明 - 这是标准的引用。

        15 一个明确的特化 模板的静态数据成员是 如果声明包括定义 初始化器;否则,它是一个 宣言。 [注意:没有语法 用于定义静态数据 需要的模板的成员 默认初始化。模板 X 问::x;这是一个声明 不管X是否可以默认 初始化(8.5)。 ]

        第二个定义应该有效。你确定你在一个编译单元中拥有所有可用的东西吗?错误信息的确切文本是什么?

        以下使用 g++ 编译/运行 - 全部在一个文件中

        #include <iostream>
        
        template < class T >
        class MyClass
        {
          public:
            static T staticObject;
            static T * staticPointerObject;
        };
        
        template < class T >
        T MyClass<T>::staticObject;
        
        template < class T >
        T * MyClass<T>::staticPointerObject = 0; 
        
        int main(int argc, char **argv)
        {
          int an_int = 5;
          MyClass<int>::staticPointerObject = &an_int;
          std::cout << *MyClass<int>::staticPointerObject << std::endl;
        
          char a_char = 'a';
          MyClass<char>::staticPointerObject = &a_char;
          std::cout << *MyClass<char>::staticPointerObject << std::endl;
        }
        

        【讨论】:

        • 我正在为 PowerPC 604 使用 GNU 交叉编译器。确切的输出是 Undefined symbol: _t16DynamicSingleton1ZQ213SingletonTest12SharedObject$ptr (binding 1 type 0) ld error: Module contains undefined symbol(s) and may be unusable .最初我在 *.cpp 文件中进行了定义,但后来我将它移到了头文件中,所以它绝对应该是可见的。我发现一些谷歌点击提到必须采取我在下面答案的第一部分中提到的步骤。我正在使用的编译器可能不支持我正在尝试做的事情(即,正是你刚刚做的事情)。
        • 我应该提到它正在与 VxWorks 5.5 链接。
        • 您能解开该错误消息中的符号吗?我的 c++filt 拒绝这样做。
        【解决方案4】:

        我找到了两种解决方案。它们都不是我所希望的 100%。

        1. 显式初始化特定实例,例如

          int * MyClass&lt;int&gt;::staticPointerObject = NULL;

        这很不方便,尤其是当我有很多不同的类型时。

        1. 将指针包裹在类中,例如
        
            template < class T >   
            class MyClass   
            {   
              private:   
                struct PointerWrapper   
                {   
                  T * pointer;   
                  PointerWrapper( void )   
                    : pointer( NULL )   
                  { }   
                };   
                T staticObject;   
                PointerWrapper staticPointerObject;   
            };   
            ...   
            template < class T >   
            T MyClass<T>::staticObject; // <-- works fine.   
            ...   
            template < class T >   
            MyClass<T>::PointerWrapper MyClass<T>::staticPointerObject; // <-- works fine.
        

        这有点麻烦,但至少可以使用。为什么我可以实例化一个变量对象但不能实例化一个指向变量对象的指针?如果有的话,我认为我会遇到更多问题(编译器提前知道指针是什么样的,但不知道我的对象是什么样的)。

        如果有人有更好的答案,我很乐意看到它!

        【讨论】:

          【解决方案5】:

          我一直使用以下技巧。这个想法是将您的静态放在一个函数中,并且只能从该函数访问它。这种方法还允许您避免在.cpp 文件中声明您的静态文件——所有内容都可以存在于.h 文件中。按照您的示例代码:

          template < class T >
          class MyClass
          {
            public:
              static T * getObject() {
                // Initialization goes here.
                static T * object = NULL; // or whatever you want
                return pointerObject;
              }
          };
          

          【讨论】:

            猜你喜欢
            • 2010-10-16
            • 1970-01-01
            • 2013-12-08
            • 2012-05-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多