статические и изменчивые квалификаторы после типа

Бьерн объясняет, почему const может идти либо до, либо после типа.

http://www.stroustrup.com/bs_faq2.html#constplacement

"const T" and "T const" were - and are - (both) allowed and equivalent.
[...]

Почему? Когда я изобрел «const» (первоначально названный «только для чтения» и соответствующий «только для записи»), я разрешил ему идти до или после типа, потому что я мог сделать это без двусмысленности.

Моя немедленная мысль была: «Хорошо, это имеет смысл, но если причина в этом, то почему const особенный?» Видимо это не так. И clang, и gcc не выдают предупреждений о следующем.

int volatile myint;
int static myotherint;

Имеет смысл, что это было бы допустимо, но я никогда не видел, чтобы этот синтаксис использовался или даже упоминался как возможность. Размещаются ли квалификаторы static и volatile после допустимого типа C++?

Как это определить из текста Стандарта?


person Praxeolitic    schedule 20.08.2014    source источник


Ответы (3)


Эти части на самом деле довольно широко разделены в стандарте. static — это класс хранения, как указано в §7.1.1/1:

storage-class-specifier:
    register
    static
    thread_local
    extern
    mutable

Он используется в определителе decl, как определено в §1.7:

decl-specifier:
    storage-class-specifier
    type-specifier
    function-specifier
    friend
    typedef
    constexpr

decl-specifier-seq:
    decl-specifier attribute-specifier-seqopt
    decl-specifier decl-specifier-seq

Таким образом, это позволяет либо static int, либо int static указать тип. Точно так же вы можете объявить функцию друга как friend int f(); или int friend f();.

const или volatile могут вмешиваться только тогда, когда вы действительно что-то объявляете, поэтому в § 8 они подпадают под «деклараторы». Эта часть грамматики достаточно длинная, мне лень ее форматировать, но она указывает declarator-list на верхнем уровне, затем declarator и (пропустив несколько уровней) опускается до cv-qualifier, что равно const или volatile. По крайней мере, насколько я читал, это в основном позволяет свободно смешивать const или volatile с другими вещами, которые определяют тип.

person Jerry Coffin    schedule 20.08.2014

Да, этот синтаксис в порядке. Первая часть грамматики объявления представляет собой последовательность спецификаторов decl. К ним относятся указания класса хранения, спецификаторы типов, указания функций, friend, typedef и constexpr. Грамматика позволяет им появляться в любом порядке. Однако накладываемые на них семантические правила вводят некоторые ограничения. Например, в объявлении переменной всегда должен быть один спецификатор типа, который не является квалификатором cv (const или volatile). Также никогда не должно быть более одного спецификатора класса хранения (за исключением того, что thread_local может появляться вместе с static или extern).

Обратите внимание, что последовательность спецификаторов decl предшествует любому синтаксису составного типа, такому как указатели, ссылки, массивы и т. д. Например, последовательность спецификаторов decl отмечена в следующих примерах:

static const int *p;
|              |

char volatile static *(&p)[20];
|                  |

Обратите внимание, что volatile является квалификатором cv, таким как const, поэтому причины для разрешения volatile в приведенном вами примере такие же, как и для const. Эти ключевые слова также могут появляться глубже в объявлении (как в int *volatile x;).

По соглашению мы сначала пишем определения класса хранения, затем указываются указания типа и квалификаторы cv, где это уместно. Я предпочитаю писать свои cv-квалификации после спецификаторов типов, которым они соответствуют, так как это более последовательно.

Вы можете прочитать Что такое объявления и деклараторы и как их типы интерпретируются стандартом?.

person Joseph Mansfield    schedule 20.08.2014

ну, вот что я думаю. я пытаюсь интерпретировать это.

static int *ptr1;
int* static ptr2;

первый означает, что это указатель, указывающий на статическое целое число. второй означает, что это статическая переменная с типом целочисленного указателя.

Я думаю, что другой способ должен иметь аналогичную интерпретацию.

person Jason Hu    schedule 20.08.2014
comment
int* static ptr2; не является допустимым объявлением. - person Joseph Mansfield; 21.08.2014
comment
@JosephMansfield, ты проверял это? будет int static *ptr3; Работа? - person Jason Hu; 21.08.2014
comment
@HuStmpHrrrr С этим все в порядке. - person Joseph Mansfield; 21.08.2014
comment
@JosephMansfield да, это похоже на статический указатель, указывающий на целое число. - person Jason Hu; 21.08.2014