статические целые, единицы компиляции и троичный оператор - PullRequest
1 голос
/ 20 декабря 2011

// 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;

Будет собираться нормально.Теперь возьмите реализацию метода () и поместите его в файл cpp:

 //SomeCls.cpp
#include "SomeCls.h"

void SomeCls::method()
    {
        bool b = true;
        const int d = b ? PERIOD_ALARM_THRESH : PERIOD_ALARM_NORMAL;
    }

Почему mr.компоновщик скажет

неопределенная ссылка на SomeCls::PERIOD_ALARM_NORMAL' undefined reference to SomeCls :: PERIOD_ALARM_THRESH '

?

Спасибо

РЕДАКТИРОВАТЬ: Кажется, чтоМне кажется, что внутри .h, троичный оператор принимает статические константы как r-значения, но ... за пределами decalrative .h он рассматривает их как l-значение и требует определения.Это то, что мне удалось понять из ответов ниже.Слава компилятору Bada (немного eabi linux thinggie)

Ответы [ 3 ]

3 голосов
/ 20 декабря 2011

Если компилятор не может видеть все значения статических констант класса , то вы должны предоставить определения для них, чтобы они действительно где-то хранились. Добавьте следующее в ваш файл cpp:

const int SomeCls::PERIOD_ALARM_NORMAL;
const int SomeCls::PERIOD_ALARM_THRESH;
2 голосов
/ 20 декабря 2011

Это ограничение GCC, но оно полностью соответствует стандарту. Технически static const int по-прежнему lvalue. Вы указали значение inline, поэтому компилятор почти всегда будет использовать его как 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.

.
1 голос
/ 20 декабря 2011

Если по какой-либо причине ваш компилятор просто отказывается связывать код (как это делает GCC 4.4.5), вот простое исправление: замените static const int s на 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, потому что оба имени являются просто псевдонимами для их соответствующих значений.

...