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

Is Type (:: x); действует?

В то время как обсуждение синтаксиса Type(identifier); и как это объявление, я столкнулся с Type(::x);, не работающим с Clang. Я ожидал бы, что с учетом глобальной переменной x он будет рассматривать ::x как выражение (::x + 2 works) и отбрасывает ::x в Type. Однако он дает ошибку компилятора.

Вот короткий пример:

int x;

int main() {
    int(::x); //does not compile
    int(::x + 2); //compiles
}

Ошибка компилятора, данная Clang 3.5:

ошибка: определение или переопределение "x" не может назвать глобальную область

GCC 4.9.0, однако, компилирует это просто отлично. Является ли этот код действительным или нет?

4b9b3361

Ответ 1

Насколько я могу судить, это распространяется на черновик стандарта С++ 8.3 Значение абзаца абзаца 6, в котором говорится (акцент мой вперед):

В объявлении T D, где D имеет вид

(D1)

тип содержащегося идентификатора-декларатора совпадает с типом содержащегося идентификатора declarator-id в декларация

T D1

Круглые скобки не изменяют тип встроенного идентификатора declarator-id, но они могут изменять привязку сложного declarators.

так:

int(::x);

эквивалентно:

int ::x ;

что явно недействительно, и это также приводит к той же ошибке. Так что gcc 4.9 здесь неверно, но поскольку это выглядит исправленным в gcc 4.8.3, который был выпущен позже, я ожидал бы, что это будет исправлено и в последующих выпусках 4.9. Хотя я не вижу никаких очевидных совпадений для этой проблемы в gcc 4.8.3 ошибках фиксированного списка, но они не утверждают, что это полный список.

Второй случай представляет собой преобразование функционального явного типа, которое рассматривается в разделе 5.2.3 Явное преобразование типа (функциональная нотация), в котором говорится:

Спецификатор простого типа (7.1.6.2) или typename-specifier (14.6) за которым следует заключенный в скобки список выражений, строит значение заданный тип с учетом списка выражений. Если список выражений является одно выражение, выражение преобразования типов эквивалентно (в определенность и определенность в значении) соответствующему литу выражение (5.4). [...]

Это однозначно, так как ::x + 2 является выражением.

Раздел, который охватывает, когда утверждение считается объявлением или выражением, является 6.8 Разрешение неоднозначности, в котором говорится:

Существует двусмысленность в грамматике, включающая выражения-выражения и объявления: выражение expression с функциональным стилем явное преобразование типа (5.2.3), поскольку его самое левое подвыражение может быть неотличимы от декларации, где начинается первый декларатор с. () В этих случаях утверждение является объявлением. [Примечание: для устранить неоднозначность, все выражение, возможно, придется изучить определить, является ли это выражением-выражением или декларацией. Эта неоднозначно много примеров.

и предоставляет следующие примеры:

T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement
T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration

Примечание: без (), тогда T ::D является квалифицированным id в случае T, являющимся классом, который рассматривается в грамматике 5.1 Первичных выражений.

Обновить

Подано сообщение gcc bug.

gcc ответ таков:

Текущий g++ и EDG рассматривают его как действительное выражение (int):: x

Поскольку этот ответ подразумевает, что clang неверен (я не согласен, хотя), я подал отчет об ошибке clang и более старый отчет об ошибках выглядит аналогичным и, похоже, не согласен с ответом gcc.

Обновление 2

В ответ на clang bug report Ричард Смит соглашается, что это следует рассматривать как декларацию и говорит:

Это не означает, что clang неверен; на самом деле, Кланг верен здесь, насколько я вижу. (Я также отправил отчет об ошибке в EDG.)

Тем не менее, мы должны дать правильный "вы нажмете на досадный синтаксический разбор, вот как чтобы устранить ошибку в этом случае.

Обновление 3

gcc подтверждает, это ошибка.

Ответ 2

Это выглядит как самый неприятный синтаксический анализ для меня. Если он может быть проанализирован как декларация, это будет. Первый может быть проанализирован как объявление переменной int (int ::x;), но :: является незаконным в этом контексте. Второй должен быть выражением, поэтому компилятор выполняет математику, передает ее в int и отбрасывает результат.

Был ли это педантичный вопрос, или есть еще одна проблема? Если у вас есть определенная проблема, которую вы пытаетесь решить, дополнительная информация позволит обходной путь для вашего варианта использования.