【问题标题】:"undefined reference" to static member of template class accessed from static method对从静态方法访问的模板类的静态成员的“未定义引用”
【发布时间】:2014-01-05 16:25:33
【问题描述】:

我有一个静态类方法,它需要访问指针 MyTypePointer,因此必须将其声明为静态。由于它是一个模板类,我必须将方法放在头文件中,但我无法在头文件中定义 MyTypePointer。

所以我得到 "undefined Reference" 错误,因为 MyTypePointer 没有声明。我怎样才能使这项工作/声明 MyTypePointer。

myclass.h

template <typename A, typename B>
class PathfindingClass {
    typedef std::vector<GenericEdgeClass<A, B>*> MyType;
    static MyType *MyTypePointer;
};

template <typename A, B>
void MyClass<A, B>::MyMethod(int x, int y) { 
    //do something with MyTypePointer
}

非常感谢。

【问题讨论】:

  • 您需要在模板声明中(在标题中)为其添加一个定义
  • 实际上,您的问题是“定义”静态成员,而不是声明它。而且我认为您必须自己在 CPP 文件中明确地为您的类模板的每个实例化执行此操作。不过我可能错了!
  • @yzt 不,它应该在标题中定义。链接器将处理多个实例化。
  • @πάνταῥεῖ:哦,谢谢!该死的,一直以来我一直在猜测链接器并为自己制造这个特殊的问题!

标签: c++ templates static


【解决方案1】:

在模板定义中,static MyType *MyTypePointer;声明一个对象。您仍然必须在模板类定义之外定义它:

template <class A, class B>
typename PathfindingClass<A, B>::MyType*
PathfindingClass<A, B>::MyTypePointer;

【讨论】:

  • 如果多个源文件包含此标头并使用相同的AB 实例化此模板,这不会导致MyTypePointer 的多个实例吗?
  • 有效!谢谢!我会花一晚上的时间来了解那里实际发生的事情。
  • @yzt - 没有。就像模板函数一样,实现负责整理重复并最终只得到一份副本。
  • @PeteBecker:哦,谢谢!该死的,一直以来我一直在猜测链接器并为自己制造这个特殊的问题!
  • 有趣!我很确定这在 C++03 中不起作用,但我可以在 14 [temp] 第 6 段中看到,显然需要在所有翻译单元中定义 static 成员导致隐式实例化...
【解决方案2】:

您仍然可以定义模板成员并为所有需要的特化显式实例化它。如果您坚持在类模板中拥有 state 数据成员,这大致就是需要的。

鉴于全局变量存在各种问题,包括初始化期间的依赖问题,您最好使用static 成员函数包装您的数据成员:

template <typenane T>
class foo {
    // ...
    static X*& member() {
        static X* rc = ...;
        return rc;
    }
};

第一次调用函数时会初始化局部变量,并且可以安全地使用对它的引用。这种方法也适用于模板。

请注意,我仍然建议避免使用全局变量!它们在长期和短期内造成许多问题,使用它们的好处是通常无法偿还的巨额债务。

【讨论】:

  • 谢谢。出于这个原因,我正在避免使用全局变量。我也猜想,在涉及模板时使用全局变量可能一开始并不那么容易? 我知道这可能不是正确的地方,但你能推荐一本解释 cpp 更复杂方面的书(de、eng、fr、it)吗?
  • @user3049681:C++ 的经典书籍是 Scott Meyers 的《Effective C++》。除此之外,还有几本书涉及各个方面,但我不知道任何一本书。关于模板“C++ Templates”似乎是最完整的一本书,但它没有涵盖 C++11 引入的更改(即,在更新之前,它应该被视为“不完整的指南”)。
【解决方案3】:

这是完整参考的较晚答案,因为此问题已链接为对另一个问题的参考。

静态字段已声明但未定义的最小损坏示例可能是:

template<typename T>
class A
{
public:
    static T val;
    static void init()
    {
        val=0;
    }
};

int main()
{
    // A::init();
    A<double>::init();
    return 0;
}

修复只是在类定义之后定义静态字段:

template<typename T>
class A
{
public:
    static T val;
    static void init()
    {
        val=0;
    }
};

template<typename T> T A<T>::val; // only change here

int main()
{
    // A::init();
    A<double>::init();
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-17
    • 2021-07-10
    相关资源
    最近更新 更多