typedef and containers of const pointers
The following line of code compiles just fine and behaves:
list<const int *> int_pointers; // (1)
The following two lines do not开发者_JS百科:
typedef int * IntPtr;
list<const IntPtr> int_pointers; // (2)
I get the exact same compile errors for
list<int * const> int_pointers; // (3)
I'm well aware that the last line is not legal since the elements of an STL container need to be assignable. Why is the compiler interpreting (2) to be the same as (3) ?
Short answer:
- is a list of pointers to constant ints.
- is a list of constant pointers to ints.
- is the same as 2.
const (and volatile) should naturally appear after the type they qualify. When you write it before, the compiler automatically rewrites it internally:
const int *
becomes
int const *
which is a pointer to a constant int. Lists of these will compile fine since the pointer itself is still assignable.
You read C-style type declarations right to left. So "const int *" is a pointer to constant ints ("const int" and "int const" mean the same thing). Those are perfectly assignable. But (2) and (3) are constant pointers to int, and therefore not assignable.
You are asking "Why is the compiler interpreting (2) to be the same as (3)?". Well, because in C++ language (as well as in C) they are semantically the same. When you define a typename as
typedef int *IntPtr;
then later the type const IntPtr
will stand for int *const
, not for const int *
. That's just how typedef-names work in C++.
Typedef-names in C++ are not macros. While they do not define new types (just aliases for the existing ones), the resulting aliases are nevertheless "atomic", "monolithic" in a sense that any qualifiers applied to the alias will apply as top-level qualifiers. When you are working with a typedef-name, there's no way to "sneak in" a const qualifier so that it would somehow "descend" to a lower-level portion of the type (int
in your case).
If you insist on using typedef-names, you have no other immediate choice but to provide two different typedef-names, like
typedef int *IntPtr;
typedef const int *ConstIntPtr;
and use ConstIntPtr
when you need a pointer-to-const version of the type.
const IntPtr
and const int*
are not the same thing.
1) const int*
is "pointer to const int
".
2) const IntPtr
expands to int * const
(think (int *) const
) which is "const
pointer to int
".
In short, the typedef
is acting like a set of parentheses. You can't change the const
-ness of what a typedef
'd pointer points to.
const int *
is the same as writing int const *
, meaning a constant value pointed by a non constant pointer.
With the typedef you define the pointer itself as constant, like in your 3rd statement.
I am sure you know that const IntPtr
and IntPtr const
are the same type.
Which means list<const IntPtr>
and list<IntPtr const>
are the same type.
Which means you are trying to compile this:
typedef int * IntPtr;
list<IntPtr const> int_pointers; // (2bis)
精彩评论