当使用 g++ 3.4.6(使用 ld 2.15.92.0.2)时,我可以写:
class ConstantContainer {
public:
static const uint16_t MyConstant1 = UINT16_C(0x4321);
static const uint32_t MyConstant2 = UINT32_C(0x87654321);
static const uint64_t MyConstant3 = UINT64_C(0xF0E1D2C3B4A59687);
static const double MyConstant4 = 1.0 / 4.0;
};
除了初始化其他常量外,几乎在所有地方都使用ConstantContainer::MyConstant1
和其他方法来代替作用域文字。
但是,当使用 g++ 3.3.6(使用相同版本 2.15.92.0.2 的 ld,尽管二进制文件和发行版不同)时,代码也可以正常编译,但在某些情况下,由于在任何时候无法解析引用,链接会失败使用“常数”:
g++ -o myapp module1.o module2.o ... main.o
moduleN.o(.text+0x59e): In function `BlahBlah(const FooBar&)':
: undefined reference to `ConstantContainer::MyConstant1'
我不知道是哪些独特的功能引起了这种行为。例如,不兼容的情况可能像这样简单:
class GraphConversionState {
public:
struct NodeIndex {
public:
typedef CxxStd::uint32_t ValueType;
ValueType Value;
class ValueSpecial {
public:
static CxxConstExpr ValueType
Unknown = UINT32_C(0xFF000000),
Isolated = UINT32_C(0xFF111111),
Connected = UINT32_C(0xFFCCCCCC);
};
};
};
IE。只有一小部分 uint 类型的静态常量成员,但它们没有资格被视为命名文字;同时,在其他情况下,即使是浮点值也可以。唯一明显的区别是范围级别(类嵌套),但在简化示例的一般情况下,这并不是真正的原因。
显而易见的解决方法是将上述类变成怪物:
class ConstantContainerType {
public:
uint16_t MyConstant1;
uint32_t MyConstant2;
uint64_t MyConstant3;
double MyConstant4;
ConstantContainerType() :
MyConstant1(UINT16_C(0x4321)),
MyConstant2(UINT32_C(0x87654321))
MyConstant3(UINT64_C(0xF0E1D2C3B4A59687))
MyConstant4(1.0 / 4.0)
{ }
};
static const ConstantContainerType ConstantContainer;
// in ConstantContainer.cpp:
const ConstantContainerType ConstantContainer;
但这很丑陋,不太干净,而且更容易出错,因为常量和容器类的数量很多。更重要的是,虽然就地声明和定义的常量可能已经优化,因为它们是真正的文字,但非常值得怀疑的是,当它们成为单例对象的一部分时,它们是否会被如此对待。
所以我想知道:GCC 3.3 及更高版本用于将一些静态 const POD 声明视为常量定义的确切规则是什么?