//  Scope of constant 


// typedef and const has internal linkage by default.
// file1:
    // bad practice...
    typedef int my_type;
    const int ci = 10;

// file2:
    // bad practice...
    typedef double my_type;
    const int ci = 20;



// but const can be declared external
// file1:
    extern const int ci = 10;

// file2:
    extern const int ci;




//
//  const correctness and pointers
//
//

       int i = 4;  // not constant, can be modified: 
           i = 5;

const int ci = 6;   // const, must be initialized
          ci = 7;   // syntax error, cannot be modified


     int *ip;
          ip = &i;
         *ip = 5;   // ok


/* now lets try a trick */
          ip = &ci; // ??
         *ip = 7;   // can I do this?

          ip = &ci; // syntax error



const int *cip = &ci; // ok 
          *cip = 7;   // syntax error


          ip = cip;   // syntax error, C++ keeps constness
         cip = ip;    // ok, but now:
        *cip = 5;     // syntax error, wherever icp points is const 


int const *icp;       // same as const int *
           icp = &i;  // ok, can assign to, icp is NOT const, *icp IS


          *icp = 5;   // syntax error, wherever icp points is const



/* pointer CONST */


int * const ipc = &i; // ipc IS const, mustbe initialized         
           *ipc = 5;  // OK, where ipc points to is NOT a const


int * const ipc2 = &ci; // syntax error, ipc is NOT pointer to const


const int * const cccp = &ci;  // const pointer to a const




/* what about class types? */


class Date
{
public:
  Date( int year = 2000, int month = 1, int day = 1);
  int getYear();
  int getMonth();
  int getDay();
  void set(int y, int m, int d);
private:
  int year;
  int month;
  int day;
};



const Date my_birthday(1963,11,11);
Date other_date; // 2000.1.1


my_birthday =  other_date;   // syntax error: my_birthday is const



/* ... but ... */


my_birthday.set(1976,11,11); // syntax error, can we assure, set do not modify?
int year = my_birthday.getYear();    // can we guarantee getYear do not modify?



class Date
{
public:
  Date( int year = 2000, int month = 1, int day = 1);
  int getYear() const;
  int getMonth() const;
  int getDay() const;
  void set(int y, int m, int d);
private:
  int year;
  int month;
  int day;
};

my_birthday.set(1976,11,11);        // syntax error
int year = my_birthday.getYear();   // ok





/* const and mutable members */



class Msg
{
public:
  Msg(const char *t);
  int getId();
private:
  const int id;
  std::string txt;
};



Msg m1("first"), m2("second");

    m1.getId() != m2.getId();



MSg::Msg(const char *t)
{
  txt = t;
  id  = getNextId();  // syntax error, id is const
}


MSg::Msg(const char *t) : id(getNextId()), txt(t)  // initialization list
{
//  txt = t;    
//  id  = getNextId();  // syntax error, id is const
}




/* Sometimes we need mutable */


struct Point
{
public:
  void getXY(int& x, int& y) const;
private:
  double xcoord;
  double ycoord;
  int    n_read;
};


void Point::getXY(int& x, int& y) const
{
  x = xcoord;
  y = ycoord;

  ++n_read;  // syntax error
}


struct Point
{
public:
  void getXY(int& x, int& y) const;
private:
  double xcoord;
  double ycoord;
  mutable int n_read;
};




struct Point
{
public:
  void getXY(int& x, int& y) const;
private:
  double xcoord;
  double ycoord;
  mutable std::mutex m;
};



void Point::getXY(int& x, int& y) const
{
  std::lock_guard<std::mutex> lock(m);  // lock m

  x = xcoord;
  y = ycoord;

}  // unlock m








//  Static constants in class 


// file: a.h
class X
{
    static const int  c1 = 7;    // ok, but remember definition
    static       int  i2 = 8;    // error: not const
    const        int  c3 = 9;    // ok since C++11
    static const int  c4 = f(2); // error unless f constexpr
    static const float f = 3.14; // error: not integral 
};

const int X::c1;  // do not repeat initializer here...