Esempio:
codice:
#include <iostream>
#include <stdexcept>

using namespace std;

// Una classe Vettore a dimensione fissata
template <typename T, unsigned int Size>
class Vettore
{
private:
    T vec[Size];
    
    /*
       Versioni interne const e non-const
    
       La versione const verrà usata:
       - quando l'operatore [] viene usato sul lato destro di un assegnamento
       - in generale quando viene richiamata la versione const dell'operatore []
       
       La versione non-const verrà usata:
       - quando l'istanza è non-const e l'operatore [] viene usato sul lato
         sinistro di un assegnamento (se l'istanza è const teoricamente verrebbe
         richiamata la versione const, ma ovviamente in tal caso l'assegnamento
         non può aver luogo)
    */
         
    
    const T& internalGetItem(unsigned int Pos) const
    {
        std::clog<<"internalGetItem const"<<std::endl;
        // Qui implementa il codice per la versione const/rvalue
        if(Pos>=Size)
            throw std::out_of_range("Pos eccessivo.");
        return vec[Pos];
    }
    
    T& internalGetItem(unsigned int Pos)
    {
        std::clog<<"internalGetItem non-const"<<std::endl;
        // Qui implementa il codice per la versione non-const/lvalue
        if(Pos>=Size)
            throw std::out_of_range("Pos eccessivo.");
        return vec[Pos];
    }
public:
    
    Vettore()
    {
        // Inizializzazione di default di tutti gli elementi del vettore interno
        for(unsigned int i=0; i<Size; i++)
            vec[i]=T();
    }
    
    // Classe proxy magica
    class SubscriptProxy
    {
    private:
        typedef Vettore<T, Size> ParentType;
        typedef T ElemType;
        // Classe genitore che andrà a richiamare per ottenere l'elemento
        ParentType & parent;
        // Posizione
        unsigned int pos;
        
        // Il costruttore non fa altro che inizializzare i campi
        // Viene tenuto privato per evitare che dall'esterno si possa istanziare
        SubscriptProxy(ParentType & Parent, unsigned int Pos) : parent(Parent), pos(Pos)
        {};
    public:        
        
        // Operatore di assegnamento (usato se la classe sta a sinistra di un
        // assegnamento) - richiama la versione non-const ed effettua
        // l'assegnamento tramite reference
        ElemType& operator=(const ElemType & NewValue)
        {
            std::clog<<"SubscriptProxy::operator=, pos="<<pos<<std::endl;
            return parent.internalGetItem(pos)=NewValue;
        }
        
        // Operatore di conversione implicita (usato se sta in un'espressione,
        // non alla sinistra di un uguale)
        operator const ElemType &() const
        {
            std::clog<<"SubscriptProxy::operator T, pos="<<pos<<std::endl;
            // Forza l'uso della versione const trasformando parent in un
            // riferimento const
            const ParentType & constParent = parent;
            return constParent.internalGetItem(pos);
        }
        
        // La classe genitore è friend così che la classe proxy possa accedere
        // ai suoi membri privati
        friend class Vettore<T, Size>;
    };
    
    // ... e viceversa (altrimenti la classe-genitore non potrebbe richiamare il
    // suo costruttore
    friend class Vettore<T, Size>::SubscriptProxy;
    
    // Versione const dell'operatore [] - semplicemente chiama la versione const
    // di internalGetItem
    const T& operator[](unsigned int Pos) const
    {
        return internalGetItem(Pos);
    }
    
    // Versione non-const dell'operatore [] - restituisce una nuova istanza
    // dell'oggetto-proxy, dicendole la posizione richiesta e dandole un
    // riferimento all'istanza della classe padre a cui andrà poi a chiedere
    // l'oggetto da restituire
    SubscriptProxy operator[](unsigned int Pos)
    {
        return SubscriptProxy(*this, Pos);
    }
};

// Prova con un riferimento costante (chiama la versione const di operator[])
void Test(const Vettore<int, 20> & Vec)
{
    cout<<Vec[0]<<endl;
}

int main()
{
    // Crea il nostro vettore
    Vettore<int, 20> v;
    // Assegnamento semplice
    v[5]=10;
    // Rilettura - nota che qui viene chiamato operator[] non-const, ma grazie
    // alla classe proxy viene chiamata la versione const di internalGetItem
    int i=v[5];
    cout<<i<<endl;
    // Assegnamento leggendo anche il valore restituito
    cout<<(v[0]=20)<<endl;
    // Rilettura (direttamente nel cout, l'operatore di conversione implicita
    // viene comunque scelto in maniera corretta)
    cout<<v[0]<<endl;
    // Passo come riferimento costante
    Test(v);
    return 0;
}
Purtroppo un problema di questo approccio è che non è possibile fare cose come
codice:
v[0]++;
v[0]+=50;
e compagnia; non si possono neanche implementare gli operatori in questione manualmente nella classe proxy, dato che a quel punto la compilazione fallirebbe se il contenitore fosse usato su tipi che non implementano gli operatori su cui questi si basano.
Anche roba di questo genere
codice:
int * ptr=&v[0];
ha comportamento peculiare: non restituisce l'indirizzo dell'elemento in questione, ma dell'oggetto-proxy temporaneo; in effetti per ottenere l'indirizzo dell'elemento bisognerebbe fare
codice:
int * ptr = & static_cast<const int &>(v[0]);