codice:
// Forward declaration dell'interfaccia
template<typename TRet, unsigned int N, typename TIdx=unsigned int>
class IMultipleBrackets;
// Classe-proxy per l'operatore []
// TRet: tipo restituito alla fine
// N: numero di quadre totale
// TIdx: tipo da usare per gli indici
// First: true se è l'istanza restituita dall'operator[] di IMultipleBrackets
// N2Magic: true se First && (NRemaining==1); necessario per distinguere il caso-base "strano" che salta fuori con N=2
template<typename TRet, unsigned int N, unsigned int NRemaining, typename TIdx, bool First=false, bool N2Magic=First&&(NRemaining==1)>
class BracketsProxy
{
// Puntatore agli indici
TIdx * indexes;
// Riferimento al "genitore" (classe di cui chiamare alla fine il metodo operatorMultipleBrackets)
IMultipleBrackets<TRet, N, TIdx> & parent;
public:
BracketsProxy(IMultipleBrackets<TRet, N, TIdx> & Parent, TIdx * Indexes)
: parent(Parent), indexes(Indexes)
{
}
BracketsProxy<TRet, N, NRemaining-1, TIdx> operator[](TIdx Idx)
{
// Memorizza l'indice ottenuto al posto giusto
indexes[N-NRemaining]=Idx;
// Restituisce il prossimo proxy-object
return BracketsProxy<TRet, N, NRemaining-1, TIdx>(parent, indexes);
}
};
// Specializzazione parziale per l'oggetto restituito dall'operator[] di IMultipleBrackets
template<typename TRet, unsigned int N, unsigned int NRemaining, typename TIdx>
class BracketsProxy<TRet, N, NRemaining, TIdx, true, false>
{
// Prima differenza rispetto al caso normale: è qui che viene allocato lo spazio per gli indici
TIdx indexes[N];
IMultipleBrackets<TRet, N, TIdx> & parent;
public:
// Il costruttore qui accetta il primo indice (ottenuto dall'operator[] di MultipleBrackets) e lo memorizza
BracketsProxy(IMultipleBrackets<TRet, N, TIdx> & Parent, TIdx FirstIndex)
: parent(Parent)
{
indexes[0]=FirstIndex;
}
// Copia-incolla del caso normale
BracketsProxy<TRet, N, NRemaining-1, TIdx> operator[](TIdx Idx)
{
indexes[N-NRemaining]=Idx;
return BracketsProxy<TRet, N, NRemaining-1, TIdx>(parent, indexes);
}
};
// Specializzazione parziale per il caso finale (NRemaining=1)
template<typename TRet, unsigned int N, typename TIdx, bool First>
class BracketsProxy<TRet, N, 1, TIdx, First, false>
{
TIdx * indexes;
IMultipleBrackets<TRet, N, TIdx> & parent;
public:
BracketsProxy(IMultipleBrackets<TRet, N, TIdx> & Parent, TIdx * Indexes)
: parent(Parent), indexes(Indexes)
{
}
// Qui richiama il metodo della classe-genitore e restituisce quel che restituisce lei
TRet& operator[](TIdx Idx)
{
indexes[N-1]=Idx;
return parent.operatorMultipleBrackets(indexes, N);
}
};
// Specializzazione parziale per il caso in cui si abbia sia First=true che NRemaining=1 (ovvero, l'unica istanziazione necessaria per il caso N=2)
template<typename TRet, unsigned int N, typename TIdx>
class BracketsProxy<TRet, N, 1, TIdx, true, true>
{
TIdx indexes[N];
IMultipleBrackets<TRet, N, TIdx> & parent;
public:
BracketsProxy(IMultipleBrackets<TRet, N, TIdx> & Parent, TIdx FirstIndex)
: parent(Parent)
{
indexes[0]=FirstIndex;
}
TRet& operator[](TIdx Idx)
{
indexes[N-1]=Idx;
return parent.operatorMultipleBrackets(indexes, N);
}
};
// Interfaccia da implementare per ottenere l'"operatorMultipleBrackets"
// Parametri template come sopra
template<typename TRet, unsigned int N, typename TIdx>
class IMultipleBrackets
{
protected:
// Necessaria per far sì che si possa richiamare nel caso finale
friend class BracketsProxy<TRet, N, 1, TIdx, false, false>;
friend class BracketsProxy<TRet, N, 1, TIdx, true, true>;
// Metodo da implementare nella classe che erediterà da IMultipleBrackets
virtual TRet & operatorMultipleBrackets(TIdx * Idx, unsigned int IdxNumber)=0;
public:
// Delega il lavoro ai BracketsProxy
virtual BracketsProxy<TRet, N, N-1, TIdx, true> operator[](TIdx FirstIdx)
{
return BracketsProxy<TRet, N, N-1, TIdx, true>(*this, FirstIdx);
}
};
poi fare l'overload delle «tante quadre» è giusto questione di ereditare da IMultipleBrackets<tipo da restituire, numero di parentesi> e ridefinire il metodo operatorMultipleBrackets