Почему статические переменные-члены не хорошо работают с троичным оператором? - PullRequest
15 голосов
/ 27 марта 2011

Вот сделка. У меня есть статический класс, который содержит несколько статических функций, используемых для получения ввода. Класс содержит закрытую статическую переменную-член для указания, вводил ли пользователь какую-либо информацию. Каждый метод ввода проверяет, ввел ли пользователь какую-либо информацию, и соответственно устанавливает переменную состояния. Я думаю, что сейчас самое время использовать троичный оператор. К сожалению, я не могу, потому что компилятору это не нравится.

Я повторил проблему, затем максимально упростил свой код, чтобы его было легче понять. Это не мой оригинальный код.

Вот мой заголовочный файл:

#include <iostream>

using namespace std;

class Test {
public:
    void go ();
private:
    static const int GOOD = 0;
    static const int BAD = 1;
};

Вот моя реализация с троичным оператором:

#include "test.h"

void Test::go () {
    int num = 3;
    int localStatus;
    localStatus = (num > 2) ? GOOD : BAD;
}

Вот основная функция:

#include <iostream>
#include "test.h"

using namespace std;

int main () {
    Test test = Test();
    test.go();
    return 0;
}

Когда я пытаюсь скомпилировать это, я получаю это сообщение об ошибке:

test.o: In function `Test::go()':
test.cpp:(.text+0x17): undefined reference to `Test::GOOD'
test.cpp:(.text+0x1f): undefined reference to `Test::BAD'
collect2: ld returned 1 exit status

Однако, если я заменю это:

localStatus = (num > 2) ? GOOD : BAD;

с этим:

if (num > 2) {
    localStatus = GOOD;
} else {
    localStatus = BAD;
}

Код компилируется и запускается, как и ожидалось. Какое неясное правило C ++ или угловой случай GCC ответственны за это безумие? (Я использую GCC 4.4.1 в Ubuntu 9.10.)

Ответы [ 3 ]

19 голосов
/ 27 марта 2011

Это в соответствии со стандартом C ++.Тернарный оператор представляет собой одно значение l, которое будет ссылаться на GOOD или BAD во время выполнения.Преобразование lvalue в rvalue не применяется немедленно ни к lvalue GOOD, ни к BAD, поэтому для вас требуется определение GOOD и BAD.

См. Отчет о проблемах с основным языком http://www.open -std.org / jtc1 / sc22 / wg21 / docs / cwg_active.html # 712 .

В качестве обходного пути,вы можете применить явное приведение к int (который читает их значения, тем самым делая преобразование lvalue в rvalue) или использовать оператор, который читает значение, например +:

localStatus = (num > 2) ? +GOOD : +BAD;
5 голосов
/ 27 марта 2011
class Test {
    static const int GOOD = 0;
    static const int BAD = 1;
};

Это только объявления ; они не являются определениями . Вам необходимо предоставить определения статических переменных-членов вне определения класса в одном из ваших файлов .cpp:

const int Test::GOOD;
const int Test::BAD;

В качестве альтернативы, для целочисленных констант часто удобнее использовать enum:

class Test {
    enum { 
        GOOD = 0,
        BAD = 1 
    };
};
1 голос
/ 27 марта 2011

Ваш код выглядит хорошо для меня.И ideone согласен: см. эту ссылку .Но это с gcc-4.3.4.Однако мой gcc-4.4.0 не принимает его.Поэтому, независимо от причины, это не очевидно.

Отредактировано для добавления: Следующий вариант компилируется в gcc-4.4.0:

int localStatus = 42 ? GOOD : BAD;

Напоминание: следующий кодне компилируется:

int localStatus = (num == 42) ? GOOD : BAD;

Так что кто-то где-то облажался.

...