// SomeCls.h
class SomeCls
{
static const int PERIOD_ALARM_NORMAL = 5;
static const int PERIOD_ALARM_THRESH = 1;
void method()
{
bool b = true;
const int d = b ? PERIOD_ALARM_THRESH : PERIOD_ALARM_NORMAL;
}
} obj;
它将构建好。现在取出method()实现并将其放在cpp文件中:
//SomeCls.cpp
#include "SomeCls.h"
void SomeCls::method()
{
bool b = true;
const int d = b ? PERIOD_ALARM_THRESH : PERIOD_ALARM_NORMAL;
}
为什么先生。链接器说
对
SomeCls::PERIOD_ALARM_NORMAL' undefined reference to
SomeCls :: PERIOD_ALARM_THRESH'的未定义引用
由于
编辑: 在我看来,在.h内部,三元运算符将静态const作为rvalues,但是......在decalrative .h之外,它将它们视为左值并需要定义。 这是我从下面的答案中设法理解的。感谢Bada编译器(一些eabi linux thinggie)
答案 0 :(得分:3)
如果编译器无法看到所有静态类常量'值,那么您必须为它们提供定义,以便它们实际存储在某处。将以下内容添加到cpp文件中:
const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
答案 1 :(得分:2)
这是GCC限制,但它完全符合标准。从技术上讲,static const int
仍为lvalue
。您已提供内联值,因此编译器几乎总是将其用作rvalue
。有一个例外。编译器为三元运算符发出的抽象指令查询lvalues
的地址。因此你看到了错误。
您可以使用enum
来解决此问题。或者,如果您使用新版本的GCC constexpr
已添加到标准中以修复此确切问题(命名和键入的右值)。
或者,您可以为链接器提供常量的定义。例如。在你的类cpp文件中添加一行像
// I wish I had constexpr
const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
作为旁注:对于类范围常量,我是static const
的坚定支持者。然后我发现MSVC不允许static const float
具有内联值。因此,您可以移植到static const
中的唯一值是整数,在这种情况下,enum
提供所有相同的功能,并保证它们永远不会以静默方式转换为lvalue
。
答案 2 :(得分:1)
如果由于某种原因,编译器只是拒绝链接代码(如GCC 4.4.5那样),这里有一个简单的修复:用static const int
替换enum
。
// someclass.h
// include guards, blabla
class SomeClass
{
enum AlarmPeriod{
PERIOD_ALARM_NORMAL = 5,
PERIOD_ALARM_THRESH = 1
};
public:
void method();
};
// someclass.cpp
#include "someclass.h"
void SomeClass::method(){
bool b = true;
const int d = b ? PERIOD_ALARM_THRESH : PERIOD_ALARM_NORMAL;
}
// main.cpp
#include "someclass.h"
int main(){
someclass sc;
sc.method();
}
这与GCC 4.4.5完全联系,后者不会链接前一版本,即使两者技术上都相同。
请注意,除其他外,您不能再使用PERIOD_ALARM_NORMAL
和PERIOD_ALARM_TRESH
的地址,因为这两个名称只是各自值的别名。