When I first encountered a type declaration like char const * const *, I’d
either curl up in a ball or spend several minutes puzzling through it. No more.
The right-left rule
Start at the identifier, sweep right translating symbols to words, then sweep left. Here’s the translation table:
| Symbol | Meaning |
|---|---|
* | pointer to |
& | reference to |
const | constant |
[] | array of |
() | function returning |
Example: char const * const * id
- Start at
id. - Sweep right: nothing.
- Sweep left:
*→ pointer to;const→ constant;*→ pointer to;const char→ constant character.
Result: “id is a pointer to a constant pointer to a constant character.”
The order of const relative to char doesn’t matter — const char * and
char const * are identical.
More examples
const double * const & id
→ “id is a reference to a constant pointer to a constant double.”
int *id[]
- Sweep right from
id:[]→ array of. - Sweep left:
*→ pointer to;int.
→ “id is an array of pointers to int.”
Parentheses
When you encounter ) while sweeping right, stop. Sweep left until you hit
the matching (, then go back outside.
int (**id)();
- Start at
id. - Sweep right, hit
)immediately — stop. - Sweep left:
*→ pointer to;*→ pointer to; hit(— stop. - Sweep right outside the parens:
()→ function returning. - Sweep left outside:
int.
→ “id is a pointer to a pointer to a function returning int.”
Cheat sheet
| Declaration | Reading |
|---|---|
int id | int |
int *id | pointer to int |
int &id | reference to int |
int * const id | constant pointer to int |
int **id | pointer to a pointer to int |
int id[][] | array of arrays of int |
int (*id[])() | array of pointers to functions returning int |
int (*id())() | function returning a pointer to a function returning int |
One final monster:
int (*(*id)(char *, double))[9][20]
→ “id is a pointer to a function taking a char* and a double, returning
a pointer to a 9-element array of 20-element arrays of int.”
This rule handles 99% of C++ declarations you’ll encounter in practice. Happy deciphering.