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

    [C++] Operatore + tra array

    Vorrei creare l'operatore binario somma tra array (a+b), che restituisce l'array c che ha in c[i] il valore a[i]+b[i].
    Come posso fare?

  2. #2
    Non direttamente con gli array. Puoi creare una classe "wrapper" dove tieni un'array e fare l'overload di operator+ (ogni volta che fai un append devi riallocare un array ecc... Esiste gia' std::string che però fa l'overload di operator=+)
    lolide
    Java Programmer

    Informati

  3. #3
    Originariamente inviato da lolide
    Non direttamente con gli array. Puoi creare una classe "wrapper" dove tieni un'array e fare l'overload di operator+ (ogni volta che fai un append devi riallocare un array ecc...
    Occhio, non chiede un append, ma una somma membro a membro (quella che è in matematica la somma di due vettori).
    Per il resto, tutto giusto, non è possibile farlo con due array "C-style", anche solo perché il tuo operatore dovrebbe restituire un array per valore, cosa non possibile.
    Per la classe wrapper, una volta ho scritto una classe che implementa un vettore di dimensione fissata a compile time che gestisca le normali operazioni matematiche su di esso ridefinendo gli operatori (per somma, differenza, prodotto per scalare, prodotto interno, meno unario), e fornendo anche qualcosina in più come metodi (norma euclidea, distanza, versore, iteratori) e operatori C++ (output su stream). Se ti interessa, ecco qui:
    codice:
    #ifndef VECTOR_HPP_INCLUDED
    #define VECTOR_HPP_INCLUDED
    // Per size_t
    #include <cstddef>
    #include <cmath>
    #include <iostream>
    #include <stdexcept>
    
    /*
        La classe Vector è un vettore in senso matematico.
        Ha una dimensione *fissata* a compile time (per cui è impossibile
        assegnare un vettore di una dimensione ad uno di un'altra) e definisce
        tutta una serie di operatori (somma, differenza, meno unario, prodotto per
        scalare, divisione per scalare) tali per cui è possibile usarlo in maniera
        "normale" in espressioni matematiche.
    */
    
    // Un piccolo trucco di metaprogrammazione per fargli prendere automaticamente
    // il tipo giusto per il prodotto per scalare.
    // Di base usa come tipo per il prodotto per scalare il tipo di base...
    template <typename TBaseType>
    class VectorTraits
    {
    public:
        // Tipo su cui si basa
        typedef TBaseType TraitsBaseType;
        // Il tipo usato per i prodotti per scalare
        typedef TBaseType TraitsScalarType;
    };
    
    template<unsigned int N, typename TBaseType=double>
    class Vector
     : public VectorTraits<TBaseType>
    {
    public:
        // La classe traits
        typedef VectorTraits<TBaseType> Traits;
        // Tipo usato per gli indici
        typedef std::size_t SizeType;
        // Lui stesso (per abbreviare)
        typedef Vector<N, TBaseType> ThisType;
        
        // "Importa" i typedef dei traits per comodità
        typedef typename Traits::TraitsBaseType BaseType;
        typedef typename Traits::TraitsScalarType ScalarType;
        
        typedef BaseType * iterator;
        typedef const BaseType * const_iterator;
    
        // Costruttore
        Vector()
        {
            // Ad un certo punto pensavo di inizializzare tutto al valore di
            // default, ma per i tipi-classe già avviene, mentre per i POD
            // who cares? :)
        }
    
        // Operatore di accesso agli elementi
        BaseType & operator[](SizeType Index)
        {
            if(Index>=N)
                throw std::out_of_range("Index out of range.");
            return v[Index];
        }
        
        // ... e relativa versione const
        const BaseType & operator[](SizeType Index) const
        {
            if(Index>=N)
                throw std::out_of_range("Index out of range.");
            return v[Index];
        }
        
        /*
            Operatori matematici
            
            Tutti gli operatori in versione non-assegnamento usano la versione
            con assegnamento restituendo il relativo oggetto temporaneo
        */
        
        // Prodotto per scalare
        ThisType operator*(const ScalarType & Right) const
        {
            ThisType ret(*this);
            return ret*=Right;
        }
        
        ThisType & operator*=(const ScalarType & Right)
        {
            for(SizeType i=0; i<N; i++)
                (*this)[i]*=Right;
            return *this;
        }
        
        // Prodotto interno
        // Applicato a Vector<Vector > potrebbe dare risultati bizzarri
        ScalarType operator*(const ThisType & Right) const
        {
            ScalarType ret=0.;
            for(SizeType i=0; i<N; i++)
                ret+=(*this)[i]*Right[i];
            return ret;
        }
        
        // La norma deriva direttamente dalla definizione del prodotto interno
        ScalarType Norm() const
        {
            return std::sqrt((*this)*(*this));
        }
        
        // Distanza = norma della differenza tra i due punti
        ScalarType Distance(const ThisType & Right) const
        {
            return ((*this)-Right).Norm();
        }
        
        // Versore = vettore/norma
        ThisType UnitVector() const
        {
            return (*this)/(this->Norm());
        }
        
        // Divisione per scalare (se applicabile)
        ThisType operator/(const ScalarType & Right) const
        {
            ThisType ret(*this);
            return ret*(1./Right);
        }
        
        ThisType & operator/=(const ScalarType & Right)
        {
            (*this)*=(1./Right);
        }
        
        // Somma
        ThisType operator+(const ThisType & Right) const
        {
            ThisType ret(*this);
            return ret+=Right;
        }
        
        ThisType & operator+=(const ThisType & Right)
        {
            for(SizeType i=0; i<N; i++)
                (*this)[i]+=Right[i];
            return (*this);
        }
        
        // Differenza
        ThisType operator-(const ThisType & Right) const
        {
            ThisType ret(*this);
            return ret-=Right;
        }
        
        ThisType & operator-=(const ThisType & Right)
        {
            for(SizeType i=0; i<N; i++)
                (*this)[i]-=Right[i];
            return (*this);
        }
        
        // Meno unario (cambio di segno)
        ThisType operator-()
        {
            ThisType ret(*this);
            for(SizeType i=0; i<N; i++)
                ret[i]=-ret[i];
            return ret;
        }
        
        // Iteratori (per l'uso tramite STL)
        iterator begin()
        {
            return v;
        }
        
        const_iterator begin() const
        {
            return v;
        }
        
        iterator end()
        {
            return v+N;
        }
        
        const_iterator end() const
        {
            return v+N;
        }
        
    protected:
        // Array interno
        BaseType v[N];
    };
    
    // Di nuovo il prodotto per scalare; necessario per far sì che si possa usare
    // anche se lo scalare sta sulla sinistra dell'espressione
    template<unsigned int N, typename TBaseType, typename TScalarType>
    Vector<N, TBaseType> operator*(const TScalarType & Left, const Vector<N, TBaseType> & Right)
    {
        // Di fatto richiama l'operatore già definito sopra
        return Right*Left;
    }
    
    // Specializzazione parziale nel caso in cui la classe base sia un Vector a
    // sua volta (il tipo scalare per un Vector di Vector resta il tipo scalare
    // dei suoi componenti)
    template<unsigned int N, typename TVectorBaseType>
    class VectorTraits< Vector<N, TVectorBaseType> >
    {
    public:
        // Tipo su cui si basa
        typedef Vector<N, TVectorBaseType> TraitsBaseType;
        // Il tipo usato per i prodotti per scalare
        typedef typename Vector<N, TVectorBaseType>::ScalarType TraitsScalarType;
    };
    
    // Scrive il vettore sullo stream di output specificato
    template<unsigned int N, typename TBaseType>
    std::ostream & operator<<(std::ostream & Os, Vector<N, TBaseType> Vec)
    {
        typedef Vector<N, TBaseType> VT;
        Os<<"{";
        for(typename VT::SizeType i=0; i<N; i++)
        {
            Os<<Vec[i];
            if(i!=N-1)
                Os<<"; ";
        }
        Os<<"}";
        return Os;
    }
    #endif
    Supporta anche dei Vector di Vector, nel qual caso il prodotto per scalare opera su tutte le componenti di tutti i sotto-Vector, mentre il prodotto interno fa cose bizzarre (di fatto restituisce la somma dei prodotti interni tra i sotto-Vector corrispondenti, che non vuol dire niente dal punto di vista matematico).
    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.