2

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

cigien
  • 57,834
  • 11
  • 73
  • 112
getsoubl
  • 808
  • 10
  • 25

1 Answers1

2

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;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • But it is needed to define a struct is called A_af and A_bf... Is any way to do this in more generic way. Using for example variadic templates? – getsoubl Dec 04 '20 at 16:12
  • @getsoubl the crucial point is that `get` is a free function and in your code it is defined twice (in either of the two template instantiations). You need to distinguish them somehow. Using two different tags instead of one seems to be the most simple. Anyhow this isn't something you *need* to do. If you want to access privates, write a getter or make them public ;) – 463035818_is_not_an_ai Dec 04 '20 at 16:17
  • @getsoubl there may exist other ways but I'm not aware of them. – Guillaume Racicot Dec 04 '20 at 16:19
  • Please don't make superfluous edits to posts. Adding block-quotes around the error message is not helpful in making the post easier to read or find, and is not even conventional. – cigien Dec 04 '20 at 16:23
  • @getsoubl "*Is any way to do this in more generic way*" - you could turn `A_af` and `A_bf` into a single templated struct: [demo](https://ideone.com/r7N4Iq) but that doesn't really gain you much, unless you have a lot of `private` fields to access, in which case you should rethink your code design. – Remy Lebeau Dec 04 '20 at 18:14