Search for an elegant and nonintrusive way to access private methods of a class
Asked Answered
R

1

3

Disclaimer: This is never meant to be used in production code. It's an exploration at the edges of C++ :)

My question is a follow up, based on a discussion with @Johannes Schaub here: calling private methods in c++.

I found a very short solution for private member access on his blog: http://bloglitb.blogspot.de/2011/12/access-to-private-members-safer.html

Here's a sample:

#include <iostream>
using namespace std;

// example class
struct A {
  A(int a, double b):_a(a),_b(b) { }
private:
  int _a;
  double _b;
  int f() { return _a; }
public:
};

//Robber template: provides a legal way to access a member
template<typename Tag, typename Tag::type M>
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};
// tag used to access A::_a
struct A_access_a 
{ 
  typedef int A::*type;
  friend type get(A_access_a);
};

// Explicit instantiation; the only place where it is legal to pass the address of a private member.
template struct Rob<A_access_a, &A::_a>;

int main() {

    A sut(42, 2.2);

    int a = sut.*get(A_access_a());
    cout << a << endl;

    return 0;
}

I wondered if this very elegant approach can be reused to access private methods from outside of a class.

What I would like to have, is the same simple approach for a method call:

struct A_access_f
{
    typedef int (A::*type)();
    friend type get(A_access_f);
};
template struct Rob<A_access_f, &A::f>;

Is it possible to make it run?

This is my best attempt till now:

typedef int (A::*pf)();
pf func = sut.*get(A_access_f());

My compiler is still complaining:

prog.cpp:45:33: error: invalid use of non-static member function pf func = sut.*get(A_access_f());

Romy answered 22/9, 2016 at 20:35 Comment(8)
I'm not sure any answer to this can ever be "elegant".Lithoid
elegant would be to make members that you want to access from outside public instead of privateSaprophagous
What is b in main?Sancho
@Martin Bonner: But it doesn't compileRomy
I meant in the main sample, and then realized your main sample was accessing the member variable, not the member functionSancho
b in main was rest from an experiment. Removed it.Romy
There is nothing elegant about what you are trying to doKlimesh
Your code snippet can be constexpr and thank you for sharing this!Cynthia
L
1

You were almost there. Here is what you should have written:

typedef int (A::*pf)();
const pf func = get(A_access_f());
int a = (sut.*func)();

Or as a (hard-to-digest) one-liner:

int a = (sut.*get(A_access_f()))();
Linked answered 23/9, 2016 at 9:8 Comment(1)
Interesting, I was playing around with the one-liner style too, but suffered with the correct syntax.Romy

© 2022 - 2024 — McMap. All rights reserved.