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

Указывает ли объявление, использующее "авто", выражение extern, использующее спецификатор конкретного типа?

Рассмотрим следующую программу:

extern int x;
auto x = 42;
int main() { }

Clang 3.5 принимает это (живое демо), GCC 4.9 и VS2013 не делают (живую демонстрацию для прежнего). Кто прав, и где правильное поведение указано в стандарте С++?

4b9b3361

Ответ 1

В этом стандарте удивительно мало. Все, что мы слышим о переобучении, это:

[C++11: 3.1/1]: Объявление (раздел 7) может вводить одно или несколько имен в блок переводов или имена редизайна, введенные предыдущими объявлениями. [..]

и единственная соответствующая часть семантики auto:

[C++11: 7.1.6.4/3]: В противном случае тип переменной выводится из ее инициализатора. [..]

(напоминая нам, что тип x равен int).

Мы знаем, что переменная должна быть дана одним и тем же типом всеми объявлениями:

[C++11: 3.5/10]: После всех настроек типов (в течение которых typedefs (7.1.3) заменяются их определениями), типы, указанные всеми объявлениями, относящимися к данной переменной или функции, должны быть идентичными, за исключением того, что объявления для объекта массива могут указывать типы массивов, которые отличаются наличием или отсутствием большой привязки массива (8.3.4). Нарушение этого правила для идентичности типа не требует диагностики.

и "после всех корректировок типов" должны заботиться о любых вопросах относительно участия auto во всем этом; моя интерпретация заключается в том, что это по сути является допустимым переопределением (и определением) x в глобальной области видимости с типом int и что Clang является правильным. Даже если мы предположим, что auto не считается "настройкой типа", поскольку диагностика не требуется, в худшем случае все перечисленные реализации совместимы по-своему.

Я считаю, что GCC и Visual Studio принимают во внимание следующее:

[C++11: 7.1.6.4/5]: Программа, использующая auto в контексте, явно не разрешенном в этом разделе, плохо сформирована.

& hellip, но я думаю, что это недальновидно. Кажется маловероятным, что стандартный язык предназначен для запрета обычных правил повторной публикации, только потому, что они не повторяются или явно не упоминаются внутри 7.1.6.4.

С++ 14 добавляет формулировку, которая относится к объявлениям функций с выведенными типами:

[C++14: 7.1.6.4/13]: Редекларации или специализации шаблона функции или функции с объявленным типом возвращаемого типа, который использует тип заполнителя, также должны использовать этот заполнитель, а не выведенный тип. [..]

По симметрии можно предположить, что в вашем случае int предполагается, что GCC и VS будут правильно отклонять программу. Однако это другая функция (поскольку вычет не может быть применен к простым объявлениям) и, следовательно, другой сценарий.

В любом случае, улучшенная стандартная формулировка поможет здесь. Я считаю это [разумно незначительным] редакторским дефектом.

Ответ 2

Я бы предположил, что ограничение в [dcl.spec.auto] p11 существует, потому что в противном случае это позволило бы:

int f();
auto f(); // What the return type here?

Дело в том, что тип undeduced type имеет тип возвращаемой функции. Не существует правил дедукции, основанных на предыдущих объявлениях, поэтому такое смешение запрещено для функций, хотя следующее было бы прекрасно:

int f();
auto f() { return 1; }

Эта проблема не существует для переменных:

extern int v;
extern auto v; // ill-formed

Любые переменные, относящиеся только к объявлениям, должны использовать тип не-заполнителя. Это означает, что если вы используете тип-заполнитель для определения v, он может быть выведен без каких-либо проблем, а затем, конечно, должен соответствовать типу не-заполнителя, используемому в первом объявлении.

extern int v;
auto v = 1; // ok, type deduced as 'int', matches first declaration.

Ответ 3

Заметка

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

Обновление clang верно

Я задал этот вопрос в твиттере, и ответ, который я получил от Ричарда Смита, был следующим:

Не является дефектом, он преднамерен, что это ограничение применяется только к выведенным типам возврата, а не к переменным типам. Для переменных это просто сокращение удобства, но вывод типа возвращаемого значения влияет на что-то более фундаментальное в отношении функций (и особенно шаблонов функций).

Таким образом, логика заключается в том, что это разрешено [dcl.spec.auto] и ограничивать это для выведенных типов возвращаемых данных. [dcl.spec.auto]p11 был добавлен, в противном случае нет ограничений и, следовательно, это не ограничивается для случая переменных.

оригинал

В настоящее время [dcl.spec.auto] явно не охватывает этот случай, но он говорит в [dcl.spec.auto] p5:

Программа, которая использует auto или decltype (auto) в контексте, явно не разрешенном в этом подпункте, плохо сформирована.

и мы видим, что это делает аналогичный случай для функций, плохо сформированных в [dcl.spec.auto] p11:

Редекларации или специализации шаблона функции или функции с объявленным типом возвращаемого типа, который использует тип заполнителя , также должны использовать этот заполнитель, а не выведенный тип. Аналогичным образом, переоценки или специализации шаблона функции или функции с объявленным типом возврата, который не использует тип заполнителя, не должны использовать местозаполнитель. [ Пример:

auto f();
auto f() { return 42; } // return type is int
auto f(); // OK
int f(); // error, cannot be overloaded with auto f()

....

Таким образом, хотя это может использовать разъяснение, как в настоящее время сформулировано, похоже, что gcc является правильным, и это плохо сформировано.