2009-03-25 2 views
4

Может кто-нибудь объяснить, почему следующий код не компилируется (на g ++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-49))?C++ enum не распознается надлежащим образом компилятором

struct X { 
public: 
    enum State { A, B, C }; 

    X(State s) {} 
}; 

int main() 
{ 
    X(X::A); 
} 

сообщение я получаю:

jjj.cpp: В функции 'INT основной()':
jjj.cpp: 10: 'XX :: A' не является статическим членом 'структура X'
jjj.cpp: 10: нет функции соответствия для вызова 'X :: X()'
jjj.cpp: 1: кандидаты: X :: X (X сопз &)
JJJ. cpp: 5: X :: X (X :: State) `

Является ли это плохой co de или ошибка компилятора?

Проблема решена Нилом + Конрадом. См. Комментарии к ответу Нейла ниже.

ответ

8
X(X::A); 

замечается A S объявление функции. Если вы действительно хотите, этот код, используйте:

(X)(X::A); 
+0

Скобки, конечно, решают проблему, но я не уверен, как это можно рассматривать как объявление функции, учитывая, что X :: A не является типом. Синтаксически это может быть тип, но тогда X x (X :: A) будет столь же неоднозначным. – Ari

+0

Мое чтение сообщения об ошибке состоит в том, что компилятор считает, что анонимный объект является копией. Вот почему это говорит о «X X :: A», а не о «X :: A». Но я не могу понять, почему он так думает. – Ari

+1

Ari: Я фактически запутался в сообщении об ошибке, потому что это то же самое, когда вы опускаете все круглые скобки, и это явно (для компилятора) объявление переменной (A типа X, внутри области X). Но это * должно * рассматриваться как объявление функции компилятором в соответствии со стандартом. –

10

вы забыли имя переменного в вашем определении:

int main() 
{ 
    X my_x(X::A); 
} 

Вашего код путает компилятор, поскольку синтаксический он не может отличить это от объявления функции (возвращение X и передавая X::A в качестве аргумента). В случае сомнений, компилятор C++ всегда неоднозначно выступает за объявление.

Решение ввести избыточные круглые скобки вокруг X, так как компилятор запрещает скобки типов (в отличие от constructo вызовов и т.д.):

(X(X::A)); 
+0

А, нет, на самом деле. Я пытаюсь создать временный. Если я добавлю другой конструктор, скажем, X (int a) {}, я могу сделать X (5); и он отлично компилируется. Это только переполнение, которое вызывает проблемы. – Ari

+0

Тогда послушайте совета Нила. –

+0

Я обновил свой ответ и дал альтернативу решению Нейла. –

0

Вы должны объявить объект как

X x(X::A); 

ошибка в коде.

0

Любой из этих двух линий работают для меня:

X obj(X::A); 
X obj2 = X(X::A); 

Как Нил Баттерворта указывает, X(X::A) в настоящее время рассматривается как объявление функции. Если вы действительно хотите анонимный объект, (X)(X::A) построит объект X и сразу же удалит его.

0

Можно, конечно, просто сделать что-то вроде этого:

int main() 
{ 
    // code 
    { 
    X temp(X::A); 
    } 
    // more code 
} 

Это было бы более удобным для чтения и в основном имеют тот же эффект.

1

Просто, чтобы было ясно, что происходит. Посмотрите на этот пример

int main() { 
    float a = 0; 
    { 
     int(a); // no-op? 
     a = 1; 
    } 
    cout << a; 
} 

Что выйдет? Ну, он выведет 0.int(a) из выше, может быть обработан двумя различными способами:

  • Cast к Int и отбрасывать результат
  • Объявляет переменную с именем a. Но игнорируйте круглые скобки вокруг идентификатора.

Компилятор, когда возникает такая ситуация, когда в выражении используется выражение в стиле функции, и оно также выглядит как объявление, оно всегда воспринимается как объявление. Когда он не может синтаксически быть объявлением (компилятор будет рассматривать всю строку, чтобы определить это), он будет считаться выражением. Таким образом, мы присваиваем внутреннему a выше, оставляя внешний a равным нулю.

Теперь ваше дело именно это. Вы пытаетесь (случайно) объявить идентификатор, называемый A в классе под названием X:

X (X::A); // parsed as X X::A; 

Компилятор затем переходит к стонать о не объявлялись конструктор по умолчанию, так как статические, так как она предполагает, что это будет, по умолчанию построено. Но даже если у вас был конструктор по умолчанию для X, он, конечно, по-прежнему ошибочен, потому что ни A не является статическим членом X, ни статикой X не может быть определена/объявлена ​​в области блока.

Вы можете сделать это не выглядеть как заявление, делая несколько вещей. Во-первых, вы можете разбить все выражение, что делает его больше не похожим на объявление. Или просто отмените тип, на который наложено. Оба этих disambiguations были упомянуты в других ответах:

(X(X::A)); (X)(X::A) 

Существует аналогичная, но отчетливая неоднозначность при попытке фактически объявить объект. Посмотрите на этот пример:

int main() { 
    float a = 0; 
    int b(int(a)); // object or function? 
} 

Поскольку int(a) может быть как декларация параметра называется a и явное преобразование (литая) флоат-переменной к междунар, компилятор снова решает, что это заявление. Таким образом, мы объявляем функцию с именем b, которая принимает целочисленный аргумент и возвращает целое число. Существует несколько возможностей устранить это, исходя из значений, указанных выше:

int b((int(a))); int b((int)a); 
Смежные вопросы