getsoubl
getsoubl

Reputation: 1055

C++::Access to more than one private members using templates trick

I am studying the following post access private member using template trick. I am wondering how the code should be modified in order to access more than one private varible I tried the following

#pragma once
template<typename Tag, typename Tag::type M>
struct Rob {
    friend typename Tag::type get( typename Tag::type) {
        return M;
    }
};
// use
struct A {
    A(int a) :a(a) { }
private:
    int a;
    int b;
};

// tag used to access A::a
template<typename Tag, typename Member>
struct TagBase {
    typedef Member type;
    friend type get(Tag);
};

struct A_f : TagBase<A_f, int A::*> { };
template struct Rob<A_f, &A::a>;
template struct Rob<A_f, &A::b>;

int main() {
   A a(42);
   std::cout << "proof: " << a.*get(A_f()) << std::endl;
}

But I get the following error

error C2084: function 'int A::* Rob<A_f,pointer-to-member(0x0)>::get(int A::* )' already has a body
 message : see previous definition of 'get'
 message : see reference to class template instantiation 'Rob<A_f,pointer-to-member(0x4)>' being compiled

This the link to the demo

Upvotes: 2

Views: 194

Answers (1)

Guillaume Racicot
Guillaume Racicot

Reputation: 41780

This is because typename Tag::type is both int A::*, so both instantiation define the same function.

To fix this, you'll need to change the example a bit so it uses multiple tag types:

#include <iostream>
 
template<typename Tag, typename Tag::type M>
struct Rob {
    // Here we receive tag directly
    friend typename Tag::type get(Tag) {
        return M;
    }
};
 
// use
struct A {
    A(int a) :a(a) { }
private:
    int a;
    int b;
};
 
// tag used to access A::a
template<typename Tag, typename Member>
struct TagBase {
    typedef Member type;
    friend type get(Tag);
};
 
struct A_af : TagBase<A_af, int A::*> { };
struct A_bf : TagBase<A_bf, int A::*> { };
 
template struct Rob<A_af, &A::a>;
template struct Rob<A_bf, &A::b>;
 
int main() {
    A a(42);
    std::cout << "proof: " << a.*get(A_bf()) << a.*get(A_af()) << std::endl;
}

Upvotes: 2

Related Questions