Visualizzazione dei risultati da 1 a 6 su 6
  1. #1

    [c++] sovraccarico operatore []...[]

    Salve!!
    so come sovraccaricare l'operatore operator[],
    ma mi servirebbe, e possibile nel c++, come sovraccaricare
    l'operatore operator[]..[] con n quadre, dove n è un qualsiasi numero
    da 2 in poi.
    Grazie!!!

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Il C++ prevede l'overload di operator [] solo con un singolo parametro, per cui quello che chiedi non si può fare.
    E' comunque possibile usare operator() per specificare più di un parametro.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  3. #3
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,462
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  4. #4
    Vi ringrazio per le vostre risposte, sperando che un giorno il c++ possa permettere
    questo tipo di sovraccaricamento!!

  5. #5
    Il punto è che il C++ non consente l'overloading dell'operatore [][] perché [][] non è un operatore, ma la doppia applicazione dell'operatore []. Per poter fare l'"overloading di [][]" bisogna fare l'overloading di [] restituendo un oggetto che a sua volta faccia l'overloading di []. Di solito questo si fa tramite un "proxy object", vedi ad esempio questo mio post:
    codice:
    template <typename T>
    class Container
    {
    private:
        // ...
    
    
    public:
    
        // Proxy object impiegato per fornire il secondo paio di parentesi quadre
        template <typename T>
        class OperatorBracketHelper
        {
            Container<T> & parent;
            size_t firstIndex;
        public:
            OperatorBracketHelper(Container<T> & Parent, size_t FirstIndex) : parent(Parent), firstIndex(FirstIndex) {}
    
            // Questo è il metodo richiamato per le "seconde parentesi"
            T & operator[](size_t SecondIndex)
            {
                // Chiama il metodo GetElement di parent, che si occuperà di recuperare l'elemento richiesto
                return parent.GetElement(firstIndex, SecondIndex);
            }
    
        }
    
        // Questo è il metodo richiamato dalle "prime parentesi"
        OperatorBracketHelper<T> operator[](size_t FirstIndex)
        {
            // Restituisce un proxy object che "sa" a che oggetto deve chiedere l'elemento
            // e qual è il primo indice (specificato in questa chiamata)
            return OperatorBracketHelper<T>(*this, FirstIndex);
        }
    
        T & GetElement(size_t FirstIndex, size_t SecondIndex)
        {
            // Qui viene effettivamente recuperato l'elemento richiesto
            // ...
        }
    };
    Amaro C++, il gusto pieno dell'undefined behavior.

  6. #6
    La cosa interessante è che con un po' di trucchi e template ricorsivi si può scrivere del codice che faccia l'overloading dell'"operatore «tante quadre»" in maniera semplice: inserendo questa roba
    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
    codice:
    #include <iostream>
    
    // Classe di test; stampa gli indici ma restituisce sempre un reference allo stesso intero
    struct Test : IMultipleBrackets<int, 5>
    {
        int a;
        int & operatorMultipleBrackets(unsigned int * Idxs, unsigned int N)
        {
            for(int i=0; i<N; i++)
                std::cout<<Idxs[i]<<" ";
            std::cout<<"\n";
            return a;
        }
    };
    
    int main()
    {
        Test t;
        t[1][2][3][4][5]=15;
        std::cout<<t.a<<"\n";
        std::cout<<t[1][5][2][4][6];
        return 0;
    }
    Fatto curioso: nonostante ci siano di mezzo cinque istanziazioni di template, chiamate a costruttori e ad operator[] per un assegnamento, il compilatore è sufficientemente furbo da ottimizzare il tutto all'inizializzazione di un array locale seguita dalla chiamata al metodo della classe:
    codice:
    	lea	rax, [rsp]
    	lea	rsi, [rsp+16]
    	mov	edx, 5
    	mov	rdi, rsp
    	mov	DWORD PTR [rsp+16], 1
    	mov	DWORD PTR [rsp+20], 2
    	mov	QWORD PTR [rsp+40], rax
    	mov	DWORD PTR [rsp+24], 3
    	mov	DWORD PTR [rsp+28], 4
    	mov	DWORD PTR [rsp+32], 5
    	call	_ZN4Test24operatorMultipleBracketsEPjj
    Amaro C++, il gusto pieno dell'undefined behavior.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.