// privateメンバへのアクセス サンプル

// 元となるコード
// https://g...content-available-to-author-only...b.com/1528856
// Accessing Private Data 
// c.f. http://b...content-available-to-author-only...t.com/2010/07/access-to-private-members-thats-easy.html

#include <iostream>

// ----------------------------------------------------------
// Accessor 
// Tag には、後述のA_mem1やA_mem2が渡される。
// Tag::type は、アクセスするメンバのメンバポインタ型となる。
template <class Tag>
struct Accessor {
    static typename Tag::type value;
};

// staticメンバの実体
// アクセスしたい型のメンバポインタを保持する。
template <class Tag>
typename Tag::type Accessor<Tag>::value;

// ----------------------------------------------------------
// Initializer
template <class Tag, typename Tag::type p>
struct Initializer {
    // コンストラクタにおいて
    // Accessor型のstaticメンバ value に p (メンバポインタ) 
    // を設定する。
    Initializer() { Accessor<Tag>::value = p; }
    static Initializer instance;
};

// 初期化を駆動するための static オブジェクト(自身)の定義
// explicit instantiation によって、int main() 前に
// 生成されることが確定し、生成の際、コンストラクタが
// 呼び出されることになる。
template <class Tag, typename Tag::type p>
Initializer<Tag, p> Initializer<Tag, p>::instance;

// ------------------------------------------------------
// Target Class
// privateメンバにアクセスされるクラス
struct A {
    A(int mem1, int mem2):mem1(mem1), mem2(mem2) {}
    void print() const { 
        std::cout << "mem1 = " << mem1 << " mem2 = " << mem2 << std::endl;
    }
private:
    int mem1;
    int mem2;
    static int smem; // static
};
int A::smem = 42; // static

// Tagクラス。アクセスするメンバの、メンバポインタ型を
// をタイプメンバ type として持つ
struct A_mem1 { typedef int A::* type; };
struct A_mem2 { typedef int A::* type; };
struct A_smem { typedef int* type; };  // static


// ------------------------------------------------------
// Template の Explicit instantiation
// ここでは private メンバにアクセスできる
// A::memのアドレスで、Initialize経由でAccessor::valueを
// 設定

// 14.7.2/12 The usual access checking rules do not apply
// to names used to specify explicit instantiations. 
// [ Note: In particular, the template arguments and 
// names used in the function declarator (including 
// parameter types,return types and exception 
// specifications) may be private types or objects 
// which would normally not be accessible and the 
// template may be a member template or member function
// which would not normally be accessible. —end note ]

template struct Initializer<A_mem1, &A::mem1>;
template struct Initializer<A_mem2, &A::mem2>;
template struct Initializer<A_smem, &A::smem>; // static

int main() {
    A a(1, 2);
    // Accessorを経由して (設定済みの )mem にアクセス
    std::cout << *Accessor<A_smem>::value << std::endl; // static
    std::cout << a.*Accessor<A_mem1>::value << std::endl;
    std::cout << a.*Accessor<A_mem2>::value << std::endl;
    a.*Accessor<A_mem1>::value = 3;
    a.*Accessor<A_mem2>::value = 4;
    a.print();
    // ちなみに、Explicit instantiation 以外の箇所では
    // private メンバにアクセスできない
    // Initializer<A, &A::mem>(); // error A::mem is private
}
// Output:
/*
42
1
2
mem1 = 3 mem2 = 4
*/
