Подтвердить что ты не робот

Странная ошибка компиляции GCC (простой пример включен)

Это довольно простой вопрос, но я не понимаю, почему приведенный ниже код не компилируется на GCC 4.6.1. Он компилируется на VS 2008 с пакетом обновления 1:

#include <iostream>

class MyClass
{
public:
    const static int MinValue = -1000;
    const static int MaxValue = 1000;
};

void printValue(int i)
{
  std::cout << i << std::endl;
}

int main(int argc, char** argv)
{
  printValue(MyClass::MinValue);
  printValue(MyClass::MaxValue);
  printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue); //This line gives the error
}

GCC говорит:

[email protected]:~/temp$ g++ test.cpp
/tmp/ccN2b95G.o: In function `main':
test.cpp:(.text+0x54): undefined reference to `MyClass::MinValue'
test.cpp:(.text+0x5c): undefined reference to `MyClass::MaxValue'
collect2: ld returned 1 exit status

Однако, если я выберу третий вызов "printValue", он строит и работает правильно. Так это как-то связано с "?" оператор... недействительно использовать его так? Кроме того, если я заменил 'argc < 42 'с "истинным" или "ложным", он также отлично работает.

Любые идеи?!

4b9b3361

Ответ 1

Вам нужно определить ваши статические члены вне объявления класса:

class MyClass
{
public:
    const static int MinValue;
    const static int MaxValue;
};


//implementation file
const int MyClass::MinValue = -1000;
const int MyClass::MaxValue = 1000;

Ответ 2

В соответствии с "Правилом одного определения" переменная должна иметь ровно одно определение, если оно используется как odr. Это определяется стандартом С++ 11:

3.2/2 Переменная или неперегруженная функция, имя которой отображается как потенциально оцениваемое выражение, используется odr, если оно не является объектом, удовлетворяющим требованиям для отображения в постоянном выражении, а преобразование lvalue-to-rvalue немедленно применяется.

и сам ODR:

3.2/3 Каждая программа должна содержать ровно одно определение каждой не-встроенной функции или переменной, которая является odr-используемой в этой программе; не требуется диагностика.

В качестве аргументов вызова функции они не используются odr: они являются константами со значением, указанным в их объявлении, и поэтому могут отображаться в постоянном выражении; и они передаются по значению и поэтому сразу преобразуются в значения r.

Это не тот случай, когда они используются в условном выражении. Поскольку оба значения lvalues ​​относятся к одному и тому же типу, результат условного выражения будет lvalue в соответствии с одним из довольно сложных правил, определяющих условный оператор:

5.16/4 Если второй и третий операнды являются glvalues ​​одной и той же категории значений и имеют один и тот же тип, результат относится к типу и категории значений.

(Это правило допускает выражения типа (a?b:c)=d.)

Таким образом, сами константы не сразу преобразуются в rvalues, и условное выражение не может появляться в постоянном выражении из-за условия выполнения; поэтому они используются как odr и поэтому нуждаются в определении.

Как вы заметили, изменение условия на константное выражение устраняет ошибку ссылки; так что изменит тип одной константы. Но выражение как таковое требует, чтобы у них было определение в одной (и только одной) единицах перевода:

const int MyClass::MinValue;
const int MyClass::MaxValue;

Ответ 3

Я собираюсь выйти на конечность и сказать, что это, вероятно, ошибка компилятора с той версией, которую вы используете. Как отметил AzzA в своем комментарии, gcc-4.5.1, похоже, прекрасно его строит, как gcc-4.3.4. Я также просто проверил это с помощью CLang 2.9, и он также принимает код.

В качестве альтернативы вы можете определить свои значения min/max с перечислениями, а не с static const. Это сохранит некоторую типизацию:

#include <iostream>

class MyClass
{
public:
    enum { MinValue = -1000, MaxValue = 1000 };
};

void printValue(const int i)
{
  std::cout << i << std::endl;
}

int main(int argc, char** argv)
{
  printValue(MyClass::MinValue);
  printValue(MyClass::MaxValue);
  printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue);
}