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)?

6 ответов

Решение

Короткий ответ:

  1. список указателей на постоянные числа
  2. список константных указателей на целые
  3. такой же, как 2.

const (и volatile) должны естественно появляться после того типа, который они квалифицируют. Когда вы пишете это раньше, компилятор автоматически переписывает это внутренне:

const int *

становится

int const *

который является указателем на константу int. Их списки будут компилироваться нормально, так как сам указатель все еще может быть назначен.

Вы читаете объявления в стиле C справа налево. Таким образом, "const int *" является указателем на постоянные целые числа ("const int" и "int const" означают одно и то же). Это прекрасно назначаемо. Но (2) и (3) являются постоянными указателями на int, и, следовательно, не присваиваются.

Вы спрашиваете "Почему компилятор интерпретирует (2) так же, как (3)?". Ну, потому что в языке C++ (как и в C) они семантически одинаковы. Когда вы определяете имя типа как

typedef int *IntPtr;

потом тип const IntPtr будет стоять за int *const, не для const int *, Именно так работают имена типов в C++.

Имена типов в C++ не являются макросами. Хотя они не определяют новые типы (только псевдонимы для существующих), полученные псевдонимы, тем не менее, являются "атомарными", "монолитными" в том смысле, что любые квалификаторы, примененные к псевдониму, будут применяться как квалификаторы верхнего уровня. Когда вы работаете с typedef-name, нет способа "проникнуть" в спецификатор const, чтобы он каким-то образом "спустился" в часть типа более низкого уровня (int в твоем случае).

Если вы настаиваете на использовании typedef-имён, у вас нет другого немедленного выбора, кроме как предоставить два разных typedef-имени, например

typedef int *IntPtr;
typedef const int *ConstIntPtr;

и использовать ConstIntPtr когда вам нужна указатель на константную версию типа.

const IntPtr а также const int* это не одно и то же.

1) const int* это "указатель на const int".

2) const IntPtr расширяется до int * const (считать (int *) const) который "const указатель на int".

Короче говоря, typedef действует как набор скобок. Вы не можете изменить const-Что из того, что typedefуказатель указывает на.

const int * так же, как писать int const *, что означает постоянное значение, на которое указывает непостоянный указатель.

С помощью typedef вы сами определяете указатель как константу, как в третьем выражении.

Я уверен, что вы знаете, что const IntPtr а также IntPtr const того же типа. Что значит list<const IntPtr> а также list<IntPtr const> того же типа. Что означает, что вы пытаетесь скомпилировать это:

typedef int * IntPtr;
         list<IntPtr const> int_pointers;  // (2bis)
Другие вопросы по тегам