C++ 静态整数、编译单元和三元运算符
//SomeCls.hC++ 静态整数、编译单元和三元运算符,c++,compilation,linker,undefined,C++,Compilation,Linker,Undefined,//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 :
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;
}
const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
linker先生为什么这么说
未定义对SomeCls::PERIOD\u ALARM\u NORMAL'的引用未定义
参考
SomeCls::周期\警报\阈值'
?
谢谢
编辑:
在我看来,在.h里面,三元运算符把静态常数作为右值,但是。。。在degrative.h之外,它将它们视为左值,需要定义。
这就是我从下面的答案中理解的。感谢Bada编译器(一些eabi linux之类的东西)如果编译器看不到所有静态类常量的值,那么您必须为它们提供定义,以便它们实际存储在某个地方。将以下内容添加到您的cpp文件:
//SomeCls.cpp
#include "SomeCls.h"
void SomeCls::method()
{
bool b = true;
const int d = b ? PERIOD_ALARM_THRESH : PERIOD_ALARM_NORMAL;
}
const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
如果编译器无法看到所有静态类常量的值,那么您必须为它们提供定义,以便它们实际存储在某个地方。将以下内容添加到您的cpp文件:
//SomeCls.cpp
#include "SomeCls.h"
void SomeCls::method()
{
bool b = true;
const int d = b ? PERIOD_ALARM_THRESH : PERIOD_ALARM_NORMAL;
}
const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
如果出于任何原因,编译器只是拒绝链接代码(如GCC 4.4.5所做的),这里有一个简单的修复方法:用
枚举替换静态常量int
s
// 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();
}
这与GCC4.4.5有着清晰的联系,GCC4.4.5与前一版本没有联系,尽管两者在技术上是相同的
请注意,除其他外,您不能再使用PERIOD\u ALARM\u NORMAL
和PERIOD\u ALARM\u TRESH
的地址,因为这两个名称只是各自值的别名。如果编译器出于任何原因拒绝链接代码(如GCC 4.4.5),这里有一个简单的修复方法:用enum
替换static const int
s
// 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();
}
这与GCC4.4.5有着清晰的联系,GCC4.4.5与前一版本没有联系,尽管两者在技术上是相同的
请注意,除其他外,您不能再使用PERIOD\u ALARM\u NORMAL
和PERIOD\u ALARM\u TRESH
的地址,因为这两个名称只是各自值的别名。这是GCC限制,但它完全是标准配置。从技术上讲,静态常量int
仍然是一个左值
。您提供了内联值,因此编译器几乎总是将其用作rvalue
。有一个例外。三元运算符编译器发出的抽象指令查询左值的地址。因此,您看到了错误
您可以使用enum
来解决这个问题。或者,如果您使用的是新版本的GCCconstexpr
,它被添加到标准中以解决这个确切的问题(命名并键入右值)
或者,您可以为链接器提供常量的定义。例如,在类cpp文件中添加a行,如
// I wish I had constexpr
const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
作为旁注:我是类范围常量的static const
的坚定支持者。然后我发现MSVC不允许值为inline的静态常量float
。因此,可以移植到静态常量中的唯一值是整数,在这种情况下,enum
s提供了所有相同的特性,并保证它们永远不会自动转换为左值
这是一个GCC限制,但它完全是标准配置。从技术上讲,静态常量int
仍然是一个左值
。您提供了内联值,因此编译器几乎总是将其用作rvalue
。有一个例外。三元运算符编译器发出的抽象指令查询左值的地址。因此,您看到了错误
您可以使用enum
来解决这个问题。或者,如果您使用的是新版本的GCCconstexpr
,它被添加到标准中以解决这个确切的问题(命名并键入右值)
或者,您可以为链接器提供常量的定义。例如,在类cpp文件中添加a行,如
// I wish I had constexpr
const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
作为旁注:我是类范围常量的static const
的坚定支持者。然后我发现MSVC不允许值为inline的静态常量float
。因此,可以移植到静态常量中的唯一值是整数,在这种情况下,enum
s提供了所有相同的特性,并保证它们永远不会自动转换为左值
,为什么链接器会这样说?你到底想把什么联系起来?@Scarlet:我想你误解了什么。OP不想测试d==b
,他想分配d
,在b
上测试。请不要对变量名使用所有的大写字母。它们传统上只用于预处理器宏(除了读起来很累之外)。@Xeo I'm blind:)删除注释以避免产生误解,谢谢。FWIW,这段代码在Clang 3.1中运行得很好,但在GCC 4.4.5中却没有。你在使用哪种编译器?当你做什么时,为什么链接器会这么说?你到底想把什么联系起来?@Scarlet:我想你误解了什么。OP不想测试d==b
,他想分配d
,在b
上测试。请不要对变量名使用所有的大写字母。它们传统上只用于预处理器宏(除了读起来很累之外)。@Xeo I'm blind:)删除注释以避免产生误解,谢谢。FWIW,这段代码在Clang 3.1中运行得很好,但在GCC 4.4.5中却没有。你在使用哪个编译器?+1,我不知道“如果它看不到它们的值”part@SethCarnegie:嗯,可能是另一种情况。。。“在好的情况下,您可能不需要定义,因为编译器已经知道这些值,并且可以在不需要实际变量的情况下将它们折叠到代码中”。。。