Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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

like image 500
Dan Hook Avatar asked Jan 27 '10 16:01

Dan Hook


4 Answers

Short answer:

  1. is a list of pointers to constant ints.
  2. is a list of constant pointers to ints.
  3. 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.

like image 177
bltxd Avatar answered Sep 30 '22 02:09

bltxd


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.

like image 31
Pontus Gagge Avatar answered Sep 30 '22 03:09

Pontus Gagge


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.

like image 38
AnT Avatar answered Sep 30 '22 03:09

AnT


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.

like image 21
Mike DeSimone Avatar answered Sep 30 '22 04:09

Mike DeSimone