Можно ли повторно объявить переменную как auto, которая выводится к тому же типу?

Разрешено ли стандартом следующее?

#include <iostream>

extern int a;
auto a = 3;

int main(int, char**)
{
    std::cout << a << std::endl;
    return 0;
}

clang принимает код. g++ жалуется на противоречивое объявление.


person Jamboree    schedule 24.05.2016    source источник
comment
Наверняка это баг g++   -  person M.M    schedule 24.05.2016
comment
Этот код также вызывает ошибку в MS Visual Studio 2012, говоря error C2371: 'a' : redefinition; different basic types.   -  person nabroyan    schedule 24.05.2016
comment
А как же: extern int a; decltype(a) a; ;)   -  person Ajay    schedule 24.05.2016
comment
@Ajay Это должно быть хорошо. Даже: внешний внутри a; decltype(a) a = 42;   -  person Arunmu    schedule 24.05.2016
comment
Это будет охвачено [basic.link]/10. После всех корректировок типов (во время которых определения типов (7.1.3) заменяются их определениями) типы, указанные во всех объявлениях, относящихся к данной переменной или функции, должны быть идентичными, . Трудно спорить с тем, что auto указывает тип, отличный от int для a , но даже если вы это утверждаете, я вполне уверен, что цель состоит в том, чтобы этот код был законным.   -  person M.M    schedule 24.05.2016
comment
@M.M: да, при условии, что разрешение auto - это настройка типов, и что бит в скобках предназначен только как пример того, что происходит во время настройки типов, а не определение этого. Я думаю, что это разница во мнениях между clang и gcc. Я не думаю, что эта фраза появляется где-либо еще в стандарте (сейчас я смотрю на С++ 11, не могу проверить и 14), поэтому я бы сказал, что как бы это ни было задумано, Стандарт оставил себя немного открытым для неправильного толкования. Хотя, возможно, я что-то упустил, это делает его точным.   -  person Steve Jessop    schedule 24.05.2016
comment
@SteveJessop в любом случае, точные тексты - это типы ... должны быть идентичными. Обратите внимание, что auto не является типом, поэтому мы не можем сказать, что они не идентичны, потому что типы int и auto являются разными типами. Текст не имеет смысла, если вы не считаете, что тип означает тип, выведенный auto   -  person M.M    schedule 24.05.2016
comment
@М.М. да, я как раз собирался отправить комментарий, говорящий то же самое. Если бы это имелось в виду так, как это читает gcc, тогда он должен был бы указать типы (если они есть) или что-то в этом роде, признавая возможность того, что одно из двух объявлений не имеет (пока) типа, потому что мы воздержались от разрешения auto. На самом деле, возможно, я должен считать, что auto уже является частью типа, указанного во втором объявлении, не говоря уже о каких-либо корректировках :-)   -  person Steve Jessop    schedule 24.05.2016
comment
@SteveJessop На самом деле мой вопрос навеян этим вопросом, на который иногда отвечает тот же человек, что и на вопрос, на который вы ссылаетесь. Интересно, что он считает одно законным, а другое нет.   -  person Jamboree    schedule 24.05.2016
comment
@M.M Ричард Смит соглашается, что это ошибка gcc см. мой ответ на другой дубликат здесь   -  person Shafik Yaghmour    schedule 17.09.2018


Ответы (2)


Мне не очень понятно из стандарта, но там же написано

раздел 7.1.6.4 спецификатор auto
Программа, использующая auto в контексте, явно не разрешенном в этом разделе, имеет неправильный формат.

Лучше прочитайте упомянутый раздел стандарта для всех разрешенных контекстов.

Учитывая это, я считаю, что g++ правильный, а clang неправильный. Но я могу ошибаться, в стандарте может быть какой-то отдельный раздел, который может подразумевать этот контекст, но я не смог его найти.

person Arunmu    schedule 24.05.2016
comment
Но auto a = 3; здесь явно разрешен контекст. Такое использование разрешено при объявлении переменных в блоке (6.3), в области пространства имен (3.3.6), [...] - person M.M; 24.05.2016
comment
Может быть, в контекстуальном смысле (к внешнему) это неприменимо? Или g++ и clang интерпретировали это по-разному, поскольку в этом случае стандартный язык кажется довольно свободным. - person Arunmu; 24.05.2016

Изменить ответ: как указано в комментариях. Проблема в этом случае в том, что написание

external int a;
auto a = 3;

то же, что писать

external int a;
int a = 3;

это означает, что у вас есть новое определение a, и это вызывает ошибку.

Первый ответ: насколько я понимаю, это нарушает части правила единого определения. В частности, я имею в виду следующее правило (со ссылкой на MISRA C++ 2008), которое гласит, что идентификатор с внешней связью всегда должен иметь только одно определение. В вашем примере у вас есть определение в текущем файле (auto a = 3;), а с внешним вы также ссылаетесь на определение в другом файле.

person cpow    schedule 24.05.2016
comment
В этом примере переменная определяется ровно один раз. Нарушения odr нет, если только auto a не противоречит исходному объявлению. Extern не нужно ссылаться на определение в другом файле. Он просто ссылается на определение в каком-то файле. Можно определить переменную в том же файле, где она была объявлена ​​как extern. - person eerorika; 24.05.2016
comment
Это правда. Но когда нет внешнего определения «внешнего int a», то это будет то же самое, что писать: extern int a; инт а = 3; что означает, что у нас также есть два определения - person cpow; 24.05.2016
comment
Джамбори показал весь код программы в вопросе. В нем есть только одно определение a. Конечно, если вы добавите больше определений, связав эту ЕП с другими ЕП, вы можете нарушить ODR, но я не думаю, что вопрос об этом, поскольку это не имеет ничего общего с auto. - person Steve Jessop; 24.05.2016
comment
@cpow extern int a; — это объявление, int a = 3; — это определение - person M.M; 24.05.2016
comment
@cpow: Нет, это не значит, что у нас есть два определения. Это ровно одно объявление и одно определение. Следовательно, полностью подчиняется ODR. - person Arunmu; 24.05.2016
comment
Иными словами, было бы очень неприятно, если бы файлы, содержащие определения имен extern, не могли включать тот же заголовочный файл, который включают все остальные, содержащий объявление extern. К счастью, им разрешено, и это все, что вы здесь видите. Это ЕП, которая содержит (одно) определение a, а также ее объявление extern. - person Steve Jessop; 24.05.2016
comment
ОДР все равно не актуален, речь идет о передекларации в рамках одного подразделения. Соответствующее правило: [basic.link]/10 - person M.M; 24.05.2016
comment
@ М.М. Верно. Настоящая проблема — это повторная декларация. Я попытался выделить это своим первым комментарием, но использовал неправильный словарь. Извините, моя вина. - person cpow; 24.05.2016
comment
@cpow extern int a; int a = 3; будет правильным кодом. Передекларация в порядке. Повторное объявление с неправильным типом недопустимо. Здесь auto будет выводиться как int, что является правильным типом, но g++ и msvc жалуются на конфликтующее объявление. Итак, вопрос в том, можно ли использовать auto в повторных декларациях. - person eerorika; 24.05.2016