Operator overloading for template class



  • Hi,

    I have written a template class 'DVector<T>' which store data as int, float double or ComplexNumber (my own class for complex operations). Now I want to overload the operator +, -, * and /.
    Here is the way I do it right now:
    @
    // file DVector.h
    DVector<int> operator+(DVector<int>& lhs, DVector<int>& rhs);

    DVector<float> operator+(DVector<int>& lhs, DVector<float>& rhs);
    DVector<float> operator+(DVector<float>& lhs, DVector<int>& rhs);
    DVector<float> operator+(DVector<float>& lhs, DVector<float>& rhs);

    DVector<double> operator+(DVector<int>& lhs, DVector<double>& rhs);
    DVector<double> operator+(DVector<double>& lhs, DVector<int>& rhs);
    DVector<double> operator+(DVector<float>& lhs, DVector<double>& rhs);
    DVector<double> operator+(DVector<double>& lhs, DVector<float>& rhs);
    DVector<double> operator+(DVector<double>& lhs, DVector<double>& rhs);

    DVector<ComplexNumber> operator+(DVector<int>& lhs, DVector<ComplexNumber>& rhs);
    DVector<ComplexNumber> operator+(DVector<ComplexNumber>& lhs, DVector<int>& rhs);
    DVector<ComplexNumber> operator+(DVector<float>& lhs, DVector<ComplexNumber>& rhs);
    DVector<ComplexNumber> operator+(DVector<ComplexNumber>& lhs, DVector<float>& rhs);
    DVector<ComplexNumber> operator+(DVector<double>& lhs, DVector<ComplexNumber>& rhs);
    DVector<ComplexNumber> operator+(DVector<ComplexNumber>& lhs, DVector<double>& rhs);
    DVector<ComplexNumber> operator+(DVector<ComplexNumber>& lhs, DVector<ComplexNumber>& rhs);
    @
    and
    @
    // file DVector.cpp
    DVector<int> operator +(DVector<int> &lhs, DVector<int> &rhs)
    {
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    } else {
    DVector<int> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(rhs.getData(i)+lhs.getData(i));
    }
    return ret;
    }
    }

    DVector<float> operator +(DVector<int> &lhs, DVector<float> &rhs)
    {
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    } else {
    DVector<float> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(rhs.getData(i)+lhs.getData(i));
    }
    return ret;
    }
    }

    DVector<float> operator +(DVector<float> &lhs, DVector<int> &rhs)
    {
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    } else {
    DVector<float> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(rhs.getData(i)+lhs.getData(i));
    }
    return ret;
    }
    }
    // ...
    @
    I guess you can see my problem without posting the rest of the declarations.

    This is realy bad to maintain, becouse there are 16 overloadings for each operator and 13 lines of code for the definition (resulting in 832 lines of code, just for basic operator overloading). And the code is the same, except for the type of the return DVector 'ret'.
    Is there a way to clean up all the mess and do it a smarter way?


  • Lifetime Qt Champion

    Hi,

    Do you mean something like

    @
    DVector<T> operator+(DVector<T> &lhs, DVector<T> &rhs)
    {
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    } else {
    DVector<T> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(rhs.getData(i)+lhs.getData(i));
    }
    return ret;
    }
    }@



  • Hi,

    yes this looks similar to what I want to have. But, if I put these code inside my dvector.cpp file I get an error:
    undefined reference to 'operator+(DVector<float>&, DVector<float>&)' I sum two float vectors for testing).

    Also, this will work only (if it work) for the 4 overloadings int+int, float+float, double+double and complex+complex.
    there is no definition for different types eg. int+float.



  • Hi,

    template must be resolved at compile time.
    This means that you shall write all your code in header file or include your cpp file at the end of header



  • Hi,

    I don't like to write the code in the header, becouse it will blow up the file and make it hard to read.

    Including the cpp file at the end of the header will results in multiple errors like:
    redefinition of 'DVector<TYPE>::DVector()' DVector<TYPE>::DVector()

    So I decide to put
    @
    template class DVector<int>;
    template class DVector<float>;
    template class DVector<double>;
    template class DVector<ComplexNumber>;
    @

    at the end of the cpp-file, as it is mentioned here:
    http://www.parashift.com/c++-faq-lite/separate-template-class-defn-from-decl.html

    this works fine for all constructors and methods, but it does not work for operator-overloading. I think it will work for operator too if it is done correctly, but I cant find my mistake.



  • Hi,

    are your 'operator+' functions members of DVector?
    If yes you must define it as
    @
    template <typename T>
    DVector<T> DVector<T>::operator+(....) {
    }
    @

    Anyway, if you read the STL sources you'll se that there's no separation between header and sources.
    Put all your code in header file could be a suitable solution

    Also if you have a look of streambuf header you'll see the source inclusion at the endo of file



  • Hi,

    the operator+ function is not part of the DVector class
    eg:
    @
    class DVector
    {
    public:
    // ...
    private:
    // ...
    }

    DVector<int> operator+(DVector<int> &lhs, DVector<int> &rhs);
    // ...
    @

    As far as I know, it is not allowed to put operator-overloading inside the class. Please correct me if I am wrong.

    Is there a difference between a definition inside ther class and outside the class (but in the header file)?
    #1:
    @
    class test
    {
    void test()
    {
    // ...
    }
    }
    @

    #2:
    @
    class test
    {
    void test();
    }

    void DVector::test()
    {
    // ...
    }
    @

    I had a look at a streambuf.h file (http://opensource.apple.com/source/gcc/gcc-937.2/libio/streambuf.h), but it seems to me, that it is not the file you mean (can't find any definition at the end of the file)



  • Hi,

    If I remember right (but I'm not sure), if you define your function inside class, the compiler try to compile as inline function.

    The header I means is the standard STL <streambuf> that (usually in /usr/include/c++/)



  • Hi,

    now I have put my definition inside the header
    @
    // Overload the + operator
    template <typename TYPE>
    DVector<TYPE> operator+(DVector<TYPE> &lhs, DVector<TYPE> &rhs){
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    } else {
    DVector<TYPE> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(rhs.getData(i)+lhs.getData(i));
    }
    return ret;
    }
    }
    @

    and it workes fine for all types of the same type (eg. int+int, double+double ...). But if there are different types, it won't work. I tried to put this code also in the header:
    @
    template <typename TYPE1, typename TYPE2>
    DVector<TYPE1> operator+(DVector<TYPE1> &lhs, DVector<TYPE2> &rhs){
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    } else {
    DVector<TYPE1> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(rhs.getData(i)+lhs.getData(i));
    }
    return ret;
    }
    }
    @

    this will work for some type-combinations. (eg. double+int) but not for all (eg. int+double). This is becouse the compiler don't know that he should use always the "higher" type as solution (int+double=double and double+int=double).

    is there a way to tell him such a thing?



  • bq. is there a way to tell him such a thing?

    I don't think there is.

    Anyway you can drop the first function, the second one will also work when TYPE1 is equal to TYPE2.

    For the remaining problems you can define explicitly the functions

    @DVector<float> operator+( DVector<int> &lhs, DVector<float> &rhs)
    {
    return rhs + lhs;
    }

    DVector<double> operator+( DVector<int> &lhs, DVector<double> &rhs)
    {
    return rhs + lhs;
    }

    DVector<double> operator+( DVector<float> &lhs, DVector<double> &rhs)
    {
    return rhs + lhs;
    }@

    this will prevent the compiler from using template functions for those cases.

    Hope it helps,
    H.



  • Hi,

    I tried this, but get an error:
    multiple definition of `operator+(DVector<int>&, DVector<float>&)'

    here is my code:
    @
    template<typename TYPE1, typename TYPE2>
    DVector<TYPE1> operator+(DVector<TYPE1> &lhs, DVector<TYPE2> &rhs){
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    }else{
    DVector<TYPE1> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(lhs.getData(i)+rhs.getData(i));
    }
    return ret;
    }
    }

    DVector<float> operator+(DVector<int> &lhs, DVector<float> &rhs){
    return rhs+lhs;
    }
    @



  • Hi,

    I tested it before my first post using Visual C++ 2010 and it works (just double checked it).

    But to be honest I don't know what C++ Standard says about that.

    Regards,
    H.



  • Hi,

    I haven't found a solution yet.

    I addet a new feature to convert all types to others (wich work very well). With this new feature I had a new idea, making just one templatefunction for same type:
    @
    template<typename TYPE>
    DVector<TYPE> operator+(DVector<TYPE> &lhs, DVector<TYPE> &rhs){
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    }else{
    DVector<TYPE> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(lhs.getData(i)+rhs.getData(i));
    }
    return ret;
    }
    }
    @

    This work also fine.
    Next I start to write overloading for all the different types:
    @
    DVector<float> operator+(DVector<int> &lhs, DVector<float> &rhs){
    return lhs.toFloat()+rhs;
    }

    DVector<float> operator+(DVector<float> &lhs, DVector<int> &rhs){
    return lhs+rhs.toFloat();
    }
    // .....
    @

    But again, I get an error:
    no match for 'operator+' (operand types are 'DVector<float>' and 'DVector<float>')
    return lhs.toFloat()+rhs;

    This is realy wired to me. If I add two float-vectors in the main.cpp this will work. But for operator-overloading it does not.

    here is another wird thing:
    @
    // this work fine:
    DVector<float> floatSum;
    floatSum = floatVect + floatVect;

    // this won't work:
    DVector<float> intFloatSum;
    intFloatSum = intVect.toFloat() + floatVect;
    @

    I get the same error:
    no match for 'operator+' (operand types are 'DVector<float>' and 'DVector<float>')
    intFloatSum = intVect.toFloat() + floatVect;

    bwt: Thanks for all help so far!



  • Hi,

    I don't know how you organized your code so I can't help you to find out what is wrong.

    I would take the code you posted on April 20 and create the function
    @template<typename TYPE1, typename TYPE2>
    DVector<TYPE1> addDVectors(DVector<TYPE1> &lhs, DVector<TYPE2> &rhs){
    static_assert( sizeof( TYPE1 ) >= sizeof( TYPE2 ), "precondition sizeof( TYPE1 ) >= sizeof( TYPE2 ) failed. Invert the parameters order!" );
    if(lhs.getLength() != rhs.getLength()){
    throw 1;
    }else{
    DVector<TYPE1> ret;
    for(unsigned int i=0; i<lhs.getLength(); ++i){
    ret.append(lhs.getData(i)+rhs.getData(i));
    }
    return ret;
    }
    }
    @

    you still need to implement each of the 16 versions of operator '+' by hand but now they are all one line long.

    Hope it helps,
    H.

    PS. On that static assertive I'm assuming that sizeof( ComplexNumber ) > sizeof( double )



  • Hi,
    thanks Arnaut,I finally bring all the operator overloading DVector<X> * DVector<Y> to work.
    But, there is a new wired thing.
    I also implement a operator overloading for DVector<X> * <Y>, where Y is of different Types (int, float, double, ComplexNumber). Here is my code:
    @
    // inside the class (*.h)
    // multiply a constant value.
    template<typename OTHERTYPE>
    DVector<TYPE> multiply(OTHERTYPE other){
    DVector<TYPE> ret;
    for(unsigned int i=0; i<getLength(); ++i){
    ret.append(getData(i)*other);
    }
    return ret;
    }

    // also inside .h but outside the class
    DVector<int> operator
    (DVector<int> &lhs, int &rhs);

    // inside .cpp
    DVector<int> operator
    (DVector<int> &lhs, int &rhs){
    return lhs.multiply(rhs);
    }
    @

    This will work fine if I write:
    @
    DVector<int> intVect;
    DVector<int> intVect3;
    int test = 3;
    intVect3 = intVect*test;
    @

    But (and this is wired for me) this won't work:
    @
    DVector<int> intVect;
    DVector<int> intVect3;
    intVect3 = intVect*3;
    @

    I get this error:
    no match for 'operator*' (operand types are 'DVector<int>' and 'int')
    intVect3 = intVect*3;


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.