これくらいならできると思う

ふーむ…なるほど。
例えば

for (i = 0 ; i < n ; ++i) {
  calc(x.fore(i), x.back(i));
}

for (i = 0 ; i < n ; ++i) {
  calc(x[i], x(n - i));
}

for (i = 0 ; i < n ; ++i) {
  calc(x[i], !x[i]);
}

とかでどうだろう。
最後の奴はoperator[]からproxyを返却させ、!proxyはrev_proxyを生成するようにして、最終的にproxy/rev_proxyのoperator T()実際に配列アクセスしてcalc(T a, T b)につじつまを合わせるかんじ。

#include <iostream>
#include <iterator>
  
using namespace std;

template <typename I>
class dblside1
{
  typedef typename iterator_traits<I>::value_type result_type;
  typedef dblside1 container;

  template <typename D>
  struct proxy_base
  {
    container& owner;

    proxy_base(container& o)
      : owner(o)
    {
    }

    result_type
    operator[] (int idx) const
    {
      return D::at(owner, idx);
    }
  };

  struct forward_accessor
  {
    static result_type
    at(container& o, int idx)
    {
       return *(o.beg + idx);
    }
  };

  struct backward_accessor
  {
    static result_type
    at(container o, int idx)
    {
       return *(o.end - idx - 1);
    }
  };

  typedef proxy_base<forward_accessor> forward_proxy;
  typedef proxy_base<backward_accessor> backward_proxy;

  I beg, end;

public:
  dblside1(I b, I e)
    : beg(b)
    , end(e)
    , fore(*this)
    , back(*this)
  {
  }

  forward_proxy fore;
  backward_proxy back;
};

template <typename I>
class dblside3
{
  typedef typename iterator_traits<I>::value_type result_type;
  typedef dblside3 container;

  template <typename F, typename R>
  struct proxy_base
  {
    container& owner;
    int idx;

    proxy_base(container& o, int i)
      : owner(o)
      , idx(i)
    {
    }

    operator result_type() const
    {
      return F::at(owner, idx);
    }

    proxy_base<R, F>
    operator! () const
    {
      return proxy_base<R, F>(owner, idx);
    }
  };

  struct forward_accessor
  {
    static result_type
    at(container& o, int idx)
    {
       return *(o.beg + idx);
    }
  };

  struct backward_accessor
  {
    static result_type
    at(container o, int idx)
    {
       return *(o.end - idx - 1);
    }
  };

  typedef proxy_base<forward_accessor, backward_accessor> forward_proxy;
  typedef proxy_base<backward_accessor, forward_accessor> backward_proxy;

  I beg, end;

public:
  dblside3(I b, I e)
    : beg(b)
    , end(e)
  {
  }

  forward_proxy
  operator[] (int idx)
  {
    return forward_proxy(*this, idx);
  }
};

void calc(int x, int y)
{
  cout << "(" << x << ", " << y << ")" << endl;
}

int
main(int argc, char **argv)
{
  int a[] = {1, 2, 3, 4, 5};
  int n = sizeof(a)/sizeof(*a);

  dblside1<int*> x(a, a+n);
  for (int i = 0 ; i < n ; ++i) {
    calc(x.fore[i], x.back[i]);
  }

  dblside3<int*> y(a, a+n);
  for (int i = 0 ; i < n ; ++i) {
    calc(y[i], !y[i]);
  }

  return 0;
}