Почему переменные статического члена хорошо сочетаются с тройным оператором?
Здесь сделка. У меня есть статический класс, который содержит несколько статических функций, используемых для ввода ввода. Класс содержит частную статическую переменную-член для указания, вводит ли пользователь какую-либо информацию. Каждый метод ввода проверяет, вводит ли пользователь какую-либо информацию и соответственно устанавливает переменную состояния. Я думаю, что это будет подходящее время для использования тернарного оператора. К сожалению, я не могу, потому что компилятору это не нравится.
Я воспроизвел проблему, а затем упростил свой код настолько, насколько это было возможно, чтобы было легко понять. Это не мой оригинальный код.
Вот мой заголовочный файл:
#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;
}
Код компилируется и выполняется, как ожидалось. Какое неясное правило С++ или GCC-уголок делаются за это безумие? (Я использую GCC 4.4.1 на Ubuntu 9.10.)
Ответы
Ответ 1
Это соответствует стандарту С++. Тернарный оператор представляет собой одно значение lvalue, которое будет ссылаться на 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;
Ответ 2
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
};
};
Ответ 3
Ваш код выглядит хорошо для меня. И ideone
соглашается: см. эту ссылку. Но это с gcc-4.3.4. Однако мой gcc-4.4.0 не принимает его. Так что какова бы ни была причина, это не очевидно.
Отредактировано для добавления: Следующий вариант компилируется под gcc-4.4.0:
int localStatus = 42 ? GOOD : BAD;
Напоминание: следующий код не компилируется:
int localStatus = (num == 42) ? GOOD : BAD;
Итак, кто-то где-то прищурился.