It\'s possible to define a pointer to a member and using this later on:
struct foo
{
int a;
int b[2];
};
int main()
{
foo bar;
int foo::*
2020 update, with actual solution:
First, the member pointers are usually implemented as "just offsets", although quite scary. Let's see an example (on g++9, arch amd64):
struct S { int a; float b[10]; };
float(S::*mptr)[10] = &S::b;
*reinterpret_cast(&mptr) //this is 4
int S::*iptr = &S::a;
*reinterpret_cast(&iptr) //this is 0
iptr = nullptr;
*reinterpret_cast(&iptr) //this seems to be 18446744073709551615 on my box
Instead you can make a bit of a wrapper (it's quite long but I didn't want to remove the convenience operators):
#include
template
class member_ptr
{
size_t off_;
public:
member_ptr() : off_(0) {}
member_ptr(size_t offset) : off_(offset) {}
/* member access */
friend const T& operator->*(const M* a, const member_ptr& p)
{ return (*a)->*p; }
friend T& operator->*(M* a, const member_ptr& p)
{ return (*a)->*p; }
/* operator.* cannot be overloaded, so just take the arrow again */
friend const T& operator->*(const M& a, const member_ptr& p)
{ return *reinterpret_cast(reinterpret_cast(&a) + p.off_); }
friend T& operator->*(M& a, const member_ptr& p)
{ return *reinterpret_cast(reinterpret_cast(&a) + p.off_); }
/* convert array access to array element access */
member_ptr::type> operator*() const
{ return member_ptr::type>(off_); }
/* the same with offset right away */
member_ptr::type> operator[](size_t offset) const
{ return member_ptr::type>(off_)+offset; }
/* some operators */
member_ptr& operator++()
{ off_ += sizeof(T); return *this; };
member_ptr& operator--()
{ off_ -= sizeof(T); return *this; };
member_ptr operator++(int)
{ member_ptr copy; off_ += sizeof(T); return copy; };
member_ptr operator--(int)
{ member_ptr copy; off_ -= sizeof(T); return copy; };
member_ptr& operator+=(size_t offset)
{ off_ += offset * sizeof(T); return *this; }
member_ptr& operator-=(size_t offset)
{ off_ -= offset * sizeof(T); return *this; }
member_ptr operator+(size_t offset) const
{ auto copy = *this; copy += offset; return copy; }
member_ptr operator-(size_t offset) const
{ auto copy = *this; copy -= offset; return copy; }
size_t offset() const { return off_; }
};
template
member_ptr make_member_ptr(T M::*a)
{ return member_ptr(reinterpret_cast(&(((M*)nullptr)->*a)));}
Now we can make the pointer to the array element directly:
auto mp = make_member_ptr(&S::b)[2];
S s;
s->*mp = 123.4;
// s.b[2] is now expectably 123.4
Finally, if you really, really like materialized references, you may get a bit haskell-lensish and make them compose:
// in class member_ptr, note transitivity of types M -> T -> TT:
template
member_ptr operator+(const member_ptr&t)
{ return member_ptr(off_ + t.offset()); }
// test:
struct A { int a; };
struct B { A arr[10]; };
B x;
auto p = make_member_ptr(&B::arr)[5] + make_member_ptr(&A::a)
x->*p = 432.1;
// x.arr[5].a is now expectably 432.1