Бьярне объясняет, почему const может идти до или после типа.
http://www.stroustrup.com/bs_faq2.html#constplacement
"const T" and "T const" were - and are - (both) allowed and equivalent. [...]
Зачем? Когда я изобрел «const» (первоначально назывался «только для чтения» и имел
соответствующий «писать только»), я позволил ему идти до или после
типа, потому что я мог бы сделать это без двусмысленности.
Моей непосредственной мыслью было: «Хорошо, это имеет смысл, но если это причина, то почему Const Special?» Видимо это не так. И clang, и gcc не выдают никаких предупреждений о следующем.
int volatile myint;
int static myotherint;
Имеет смысл, что это будет допустимо, но я никогда не видел, чтобы этот синтаксис использовался или даже упоминался как возможность. Размещает ли статические и изменчивые квалификаторы после допустимого типа C ++?
Как определить это по тексту Стандарта?
Эти части на самом деле довольно широко разделены в стандарте. static
класс хранения, как указано в §7.1.1 / 1:
storage-class-specifier:
register
static
thread_local
extern
mutable
Это используется в Децл спецификатор, как определено в §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. Эта часть грамматики достаточно длинная, я слишком ленив, чтобы все это отформатировать, но она определяет INIT-описатель-лист на верхнем уровне, то описатель, и (пропуская несколько уровней) сводится к cv-qualifier
который либо const
или же volatile
, По крайней мере, на мой взгляд, это в основном позволяет const
или же volatile
быть свободно смешанным с другими вещами, которые определяют тип.
Да, этот синтаксис в порядке. Первая часть декларации грамматики представляет собой последовательность Децл-спецификаторы. К ним относятся классы хранения, спецификаторы типов, функции, 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-квалификации после спецификаторы типа, которым они соответствуют, так как они более последовательны.
Вы можете прочитать Что такое объявления и деклараторы и как их типы интерпретируются стандартом?.
ну, вот что я думаю. я пытаюсь это интерпретировать.
static int *ptr1;
int* static ptr2;
Первый означает, что это указатель, указывающий на статическое целое число.
второй означает, что это статическая переменная с типом целочисленного указателя.
я думаю, что другой путь должен иметь аналогичную интерпретацию.