繁体   English   中英

为什么在头文件中声明“static const”成员会导致链接器错误?

[英]Why does declaring a “static const” member in a header file cause linker errors?

我有一个类声明(.h文件),如下所示:

struct MyClass {
    static const uint32_t SIZE = sizeof(MyType);
};

将我的程序链接在一起时,我得到了MyClass::SIZE链接器错误。 nm确认符号未定义。 http://forums.devshed.com/c-programming-42/linker-errors-undefined-reference-to-static-member-data-193010.html似乎解决了我的问题,表明“类静态对象也必须是在正常的全局变量之外在任何函数或类之外声明。“

我有两个问题:

  1. 这个解释对我的案子有效吗? 如果是这样,你能更详细地解释为什么这是真的吗?
  2. 解决它的最佳方法是什么? 我想将此成员的初始化完全保留在.h文件中。

您的问题可能与获取变量地址的人无关。 它可能只是编译器选择不使用变量作为常量表达式,即使它可以。 例如:

f(int const&);
struct X { enum { enum_val = 42 }; static int const static_mem = 42; };

f(5);
f(X::enum_val);
f(X::static_mem);

在前两种情况下,编译器需要将输入用作常量表达式,并且const&可以用这样的方式初始化。 然而最后一种情况则不同。 即使你的意图可能是使用static_mem作为常量表达式,并且它完全合法,编译器也可以自由地执行,有些实际上会创建对变量本身的引用。 这是变量的“使用”,因此您需要在程序中的某处定义该变量。

有两种方法可以解决此问题:

1)为程序添加定义。

2)使用enum代替:struct X {enum {static_mem =? }; };

如果您打算采用变量的地址,那么第一个解决方案是必要的。 有可能你没有,或者你已经创建了那个定义。 后面的解决方案强制编译器使用X::static_mem作为常量表达式,因为枚举成员实际上并不作为程序中的对象存在。 根据你在问题中的最后陈述,我打赌这是你真正想要的解决方案。

标准要求静态成员积分常量的定义仅在其地址被采用时,否则使用初始化器(您拥有的)的声明就足够了。 该链接器错误消息应该提到哪个对象/函数采用MyClass::SIZE的地址。

如果你这样做:

//.h file
struct MyClass 
{
    static const uint32_t SIZE = sizeof(MyType); //this is declaration!

}; 

//.cpp file
const uint32_t MyClass::SIZE; //this is definition - necessary!

引用自己没有可用于初始化器的静态const成员的定义?

从9.4.2 / 4:

如果静态数据成员是const integral或const枚举类型,则它在类定义中的声明可以指定一个常量初始值设定项,它应该是一个整型常量表达式(5.19)。 在这种情况下,成员可以在其范围内出现在整数常量表达式中。 如果在程序中使用该成员,并且名称空间范围定义不包含初始化程序 ,则该成员仍应在名称空间作用域中定义。

从这些参考文献中我们可以推断出(“......仍然应该在9.4.2 / 4中定义......”),如果它没有定义,那么程序就没有格式良好。

@DavidRodríguez - dribeas指出你必须在你的程序中获取静态成员的地址。 如果你可以避免使用地址,那么就不需要在实现文件中定义(或者你没有获取地址并且有一个错误的编译器)。 否则你必须有定义。

  1. 很可能,但没有任何错误信息,很难说。

  2. 使用静态const int。 您可以在标题中初始化它,而不需要在cpp中声明它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM