#include<bits/stdc++.h>

using namespace std;

namespace ADL {
  struct Data  { int x; };
  void print(Data data) { cout << data.x << endl; }
}


int I  = 42;
const int CI = I; // OK!

int* pI  = &I;
const int* pCI = pI; // OK!
const int* ppp = &CI;

int** ppI  = &pI;
//const int** ppCI = ppI; // ?????????????????¨??????! int** ?????? const int** ?????????????????§????????????!

/*
int* - pointer to int
int const * - pointer to const int
int * const - const pointer to int
int const * const - const pointer to const int
Now the first const can be on either side of the type so:

const int * == int const *
const int * const == int const * const
If you want to go really crazy you can do things like this:

int ** - pointer to pointer to int
int ** const - a const pointer to a pointer to an int
int * const * - a pointer to a const pointer to an int
int const ** - a pointer to a pointer to a const int
int * const * const - a const pointer to a const pointer to an int

 */

int main() {
  auto int x = 123;
  const int v = 215;
  ppp = &v;
  pCI = &v;
  cout << *ppp << endl;
  cout << *pCI << endl;
  
  cout << *pCI << endl;
  I = 51;
  cout << *pCI << endl;
  cout << **ppI << endl;
  return 0;

  ADL::Data data = (ADL::Data){5};
  print(data); // Argment dependent lookup (ADL)
  
  return 0;
}