Typedef и контейнеры константных указателей
Следующая строка кода компилируется просто отлично и ведет себя:
list<const int *> int_pointers; // (1)
В следующих двух строках нет:
typedef int * IntPtr;
list<const IntPtr> int_pointers; // (2)
Я получаю точно такие же ошибки компиляции для
list<int * const> int_pointers; // (3)
Мне хорошо известно, что последняя строка не является законной, так как элементы контейнера STL должны быть назначаемыми. Почему интерпретация компилятора (2) совпадает с (3)?
Ответы
Ответ 1
Короткий ответ:
- - список указателей на константные int.
- - это список постоянных указателей на ints.
- совпадает с 2.
const (и volatile) должен естественным образом появляться после того, как они квалифицируются.
Когда вы пишете это раньше, компилятор автоматически перезаписывает его внутри:
const int *
становится
int const *
который является указателем на константу int. Списки из них будут компилироваться отлично, поскольку сам указатель по-прежнему можно назначить.
Ответ 2
Вы читаете декларации типа C справа налево. Таким образом, "const int *" является указателем на константу ints ( "const int" и "int const" означает одно и то же). Это прекрасно назначается. Но (2) и (3) являются постоянными указателями на int и поэтому не присваиваются.
Ответ 3
const IntPtr
и const int*
- это не одно и то же.
1) const int*
является "указателем на const int
".
2) const IntPtr
расширяется до int * const
(думаю (int *) const
), который является "const
указателем на int
".
Короче говоря, typedef
действует как набор круглых скобок. Вы не можете изменить const
-ness того, на что указывает указатель typedef
'd.
Ответ 4
Вы спрашиваете: "Почему интерпретация компилятора (2) совпадает с (3)?". Ну, потому что на языке С++ (а также в C) они семантически одинаковы. Когда вы определяете имя типа
typedef int *IntPtr;
то позже тип const IntPtr
будет стоять за int *const
, а не для const int *
. Это то, как typedef-имена работают на С++.
Typedef-имена в С++ не являются макросами. Хотя они не определяют новые типы (просто псевдонимы для существующих), полученные псевдонимы все же "атомные", "монолитные", в том смысле, что любые квалификаторы, применяемые к псевдониму, будут применяться в качестве квалификаторов верхнего уровня. Когда вы работаете с typedef-name, нет никакого способа "прокрасться" в спецификатор const, чтобы он каким-то образом "спустился" к более низкоуровневой части типа (int
в вашем случае).
Если вы настаиваете на использовании typedef-имен, у вас нет другого непосредственного выбора, кроме как предоставить два разных имени typedef, например
typedef int *IntPtr;
typedef const int *ConstIntPtr;
и используйте ConstIntPtr
, когда вам нужна версия типа указателя на константу.
Ответ 5
const int *
- это то же самое, что и запись int const *
, что означает постоянное значение, указанное указателем не константы.
С помощью typedef вы определяете сам указатель как постоянный, как в своем третьем выражении.
Ответ 6
Я уверен, вы знаете, что const IntPtr
и IntPtr const
- это один и тот же тип.
Это означает, что list<const IntPtr>
и list<IntPtr const>
являются одним и тем же типом.
Это означает, что вы пытаетесь скомпилировать это:
typedef int * IntPtr;
list<IntPtr const> int_pointers; // (2bis)