При использовании г ++ 3.4.6 (с ЛД 2.15.92.0.2), можно написать:Имея статические константные переменные с GCC 3.3 аналогично GCC 3.4
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
и другие почти везде, как заменяют подменю для замеченных литералов, за исключением инициализации других констант.
Однако при использовании г ++ 3.3.6 (с л.д. тех же версий 2.15.92.0.2, хотя и не такие же бинарное и дистрибутив), код компилируется нормально, тоже, но сшивание не может в некоторых случаях из-за чтобы неразрешенной ссылки на какой-либо точке «константа» используется:
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);
};
};
};
I. e. существует только небольшая группа статических константных членов типа 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 и выше для обработки некоторых статических константных объявлений POD как постоянных определений?
Очевидный вопрос: нужны ли вам компиляторы gcc-3.x? –
@BrettHale К сожалению, я должен поддерживать такую старую версию - просто потому, что она доступна только на целевой платформе. Я пытаюсь написать будущий код, используя кучу '# define's (a la Boost), но некоторые фундаментальные понятия, подобные этому, нельзя легко эмулировать. –
Я считаю, что 'static const =' отлично в C++ 98, если это * интегральный * тип. Но вам нужна 'const A :: B;' в единицах перевода, на всякий случай кто-то использует: '& A :: B'. Вам может просто повезти с gcc-3.4.x - то есть он выполняет постоянную фальцовку; тогда как gcc-3.3.x пытается получить доступ к постоянному объекту. [ref] (http://www.parashift.com/c++-faq/static-const-with-initializers.html), [подробнее] (http://stackoverflow.com/questions/177437/constststatic) –