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<uintptr_t *>(&mptr)  //this is 4
int S::*iptr = &S::a;
*reinterpret_cast<uintptr_t *>(&iptr)  //this is 0
iptr = nullptr;
*reinterpret_cast<uintptr_t *>(&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 <type_traits>
template<class M, typename T>
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<M, T>& p)
    { return (*a)->*p; }
    friend T& operator->*(M* a, const member_ptr<M, T>& p)
    { return (*a)->*p; }
    /* operator.* cannot be overloaded, so just take the arrow again */
    friend const T& operator->*(const M& a, const member_ptr<M, T>& p)
    { return *reinterpret_cast<const T*>(reinterpret_cast<const char*>(&a) + p.off_); }
    friend T& operator->*(M& a, const member_ptr<M, T>& p)
    { return *reinterpret_cast<T*>(reinterpret_cast<char*>(&a) + p.off_); }
    /* convert array access to array element access */
    member_ptr<M, typename std::remove_extent<T>::type> operator*() const
    { return member_ptr<M, typename std::remove_extent<T>::type>(off_); }
    /* the same with offset right away */
    member_ptr<M, typename std::remove_extent<T>::type> operator[](size_t offset) const
    { return member_ptr<M, typename std::remove_extent<T>::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<class M, typename T>
member_ptr<M, T> make_member_ptr(T M::*a)
{ return member_ptr<M, T>(reinterpret_cast<uintptr_t>(&(((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<class TT>
    member_ptr<M,TT> operator+(const member_ptr<T,TT>&t)
    { return member_ptr<M,TT>(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
                                                                        You can't do that out of the language itself. But you can with boost. Bind a functor to some element of that array and assign it to a boost::function:
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
struct test {
    int array[3];
};
int main() {
    namespace lmb = boost::lambda;
    // create functor that returns test::array[1]
    boost::function<int&(test&)> f;
    f = lmb::bind(&test::array, lmb::_1)[1];
    test t = {{ 11, 22, 33 }};
    std::cout << f(t) << std::endl; // 22
    f(t) = 44;
    std::cout << t.array[1] << std::endl; // 44
}
                                                                        The problem is that, accessing an item in an array is another level of indirection from accessing a plain int. If that array was a pointer instead you wouldn't expect to be able to access the int through a member pointer.
struct foo
{
  int a;
  int *b;
};
int main()
{
  foo bar;
  int foo::* aptr=&(*foo::b); // You can't do this either!
  bar.a=1;
  std::cout << bar.*aptr << std::endl;
}
What you can do is define member functions that return the int you want:
struct foo
{
  int a;
  int *b;
  int c[2];
  int &GetA() { return a; } // changed to return references so you can modify the values
  int &Getb() { return *b; }
  template <int index>
  int &GetC() { return c[index]; }
};
typedef long &(Test::*IntAccessor)();
void SetValue(foo &f, IntAccessor ptr, int newValue)
{  
    cout << "Value before: " << f.*ptr();
    f.*ptr() = newValue;
    cout << "Value after: " << f.*ptr();
}
int main()
{
  IntAccessor aptr=&foo::GetA;
  IntAccessor bptr=&foo::GetB;
  IntAccessor cptr=&foo::GetC<1>;
  int local;
  foo bar;
  bar.a=1;
  bar.b = &local;
  bar.c[1] = 2;
  SetValue(bar, aptr, 2);
  SetValue(bar, bptr, 3);
  SetValue(bar, cptr, 4);
  SetValue(bar, &foo::GetC<0>, 5);
}
Then you at least have a consistent interface to allow you to change different values for foo.
However, the compiler just complains about an "invalid use of non-static data member 'foo::b'"
This is because foo::a and foo::b have different types. More specifically, foo::b is an array of size 2 of ints. Your pointer declaration has to be compatible i.e:
int (foo::*aptr)[2]=&foo::b;
Is it possible to do this at all (or at least without unions)?
Yes, see below:
struct foo
{
  int a;
  int b[2];
};
int main()
{
  foo bar;
  int (foo::*aptr)[2]=&foo::b;
  /* this is a plain int pointer */
  int *bptr=&((bar.*aptr)[1]);
  bar.a=1; 
  bar.b[0] = 2;
  bar.b[1] = 11;
  std::cout << (bar.*aptr)[1] << std::endl;
  std::cout << *bptr << std::endl;
}
Updated post with OP's requirements.
I'm not sure if this will work for you or not, but I wanted to do a similar thing and got around it by approaching the problem from another direction. In my class I had several objects that I wanted to be accessible via a named identifier or iterated over in a loop. Instead of creating member pointers to the objects somewhere in the array, I simply declared all of the objects individually and created a static array of member pointers to the objects.
Like so:
struct obj
{
    int somestuff;
    double someotherstuff;
};
class foo
{
  public:
    obj apples;
    obj bananas;
    obj oranges;
    static obj foo::* fruit[3];
    void bar();
};
obj foo::* foo::fruit[3] = { &foo::apples, &foo::bananas, &foo::oranges };
void foo::bar()
{
    apples.somestuff = 0;
    (this->*(fruit[0])).somestuff = 5;
    if( apples.somestuff != 5 )
    {
        // fail!
    }
    else
    {
        // success!
    }
}
int main()
{
    foo blee;
    blee.bar();
    return 0;
}
It seems to work for me. I hope that helps.
  typedef int (foo::*b_member_ptr)[2];
  b_member_ptr c= &foo::b;
all works.
small trick for member and function pointers usage.
try to write 
char c = &foo::b; // or any other function or member pointer
and in compiller error you will see expected type, for your case int (foo::*)[2].
EDIT
I'm not sure that what you want is legal without this pointer. For add 1 offset to your pointer you should get pointer on array from your pointer on member array. But you can dereference member pointer without this.