Home > front end >  Sort vector of custom template class
Sort vector of custom template class

Time:05-13

Suppose I have a template class ComplexNumber that looks like this:

template<typename T>
class ComplexNumber {
public:
    ComplexNumber() : A(), B() {}
    ComplexNumber(const T& r, const T& i) : A(r), B(i) {}
    ~ComplexNumber(){}

    void setA(T A1);
    void SetB(T B1);
    T getA() const {return A;};
    T getB()const {return B;};

    ComplexNumber<T> operator (const ComplexNumber<T> &C){
        return ComplexNumber<T>( A   C.getA(), B   C.getB());
    }

    ComplexNumber<T> operator -(const ComplexNumber<T> &C) {
        return ComplexNumber<T>(A - C.getA(), B - C.getB());
    };

    friend ostream & operator << (ostream &out, const ComplexNumber<T> &c)
    {
        out << c.A;
        out << " i" << c.B << endl;
        return out;
    }

private:
    T A;
    T B;
};

And a main() that constructs these complex numbers and stores them into a std::vector:

ComplexNumber<int> complex1(10, 3);
ComplexNumber<int> complex2(2, 56);
ComplexNumber<int> complex3(3, 55);

vector<ComplexNumber<int>> testVector;
testVector.push_back(complex1);
testVector.push_back(complex2);
testVector.push_back(complex3);

If I want to sort testVector from highest to lowest, comparing the real parts and then comparing the imaginary ones if the real parts are equal, how would I go about doing that?

I am unable to use the standard std::sort() function. I would like to do this using a method or functor.

EDIT: Trying to add it to a function:

//This method is outside the scope of the ComplexNumber class

auto compare_by_magnitude = [](const auto& a, const auto& b) {
    return a.A*a.A   a.B*a.B < b.A*b.A   b.B*b.B;
};

void sortComplex(vector<ComplexNumber<int>> &c){
    std::sort(c.begin(),c.end(),compare_by_magnitude);
}

My error messages:

FAILED: complexNumber.exe 
cmd.exe /C "cd . && C:\PROGRA~1\JETBRA~1\CLION2~1.3\bin\mingw\bin\G__~1.EXE -g  CMakeFiles/complexNumber.dir/main.cpp.obj CMakeFiles/complexNumber.dir/ComplexNumber.cpp.obj -o complexNumber.exe -Wl,--out-implib,libcomplexNumber.dll.a -Wl,--major-image-version,0,--minor-image-version,0  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
C:\Program Files\JetBrains\CLion 2021.3.3\bin\mingw\bin/ld.exe: CMakeFiles/complexNumber.dir/ComplexNumber.cpp.obj: in function `ComplexNumber<int>::~ComplexNumber()':
C:/PROGRA~1/JETBRA~1/CLION2~1.3/bin/mingw/lib/gcc/x86_64-w64-mingw32/11.2.0/include/c  /bits/stl_heap.h:223: multiple definition of `sortComplex(std::vector<ComplexNumber<int>, std::allocator<ComplexNumber<int> > >&)'; CMakeFiles/complexNumber.dir/main.cpp.obj:C:/Users/elira/Desktop/complexNumber/complexNumber/ComplexNumber.h:51: first defined here
C:\Program Files\JetBrains\CLion 2021.3.3\bin\mingw\bin/ld.exe: CMakeFiles/complexNumber.dir/ComplexNumber.cpp.obj:C:/Users/elira/Desktop/complexNumber/complexNumber/ComplexNumber.h:48: multiple definition of `compare_by_magnitude'; CMakeFiles/complexNumber.dir/main.cpp.obj:C:/Users/elira/Desktop/complexNumber/complexNumber/ComplexNumber.h:48: first defined here
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

CodePudding user response:

In order to work with std::sort(), your class needs at least operator< defined:

bool operator< (const ComplexNumber<T>& other) const {
    return A < other.A || (A == other.A && B < other.B);
}

It's also good practice to define operator==, but std::sort() will work with operator< alone.

When I make the above addition to your class, this main() sorts by real and then imaginary, in ascending order:

int main() {
    vector<ComplexNumber<float>> vc = { {4, 5}, {1, 3}, {4, 2} };
    copy(vc.begin(), vc.end(), ostream_iterator<ComplexNumber<float>>(cout, " "));
    cout << endl;
    sort(vc.begin(), vc.end());
    copy(vc.begin(), vc.end(), ostream_iterator<ComplexNumber<float>>(cout, " "));
    cout << endl;
}

But, you mentioned you want to sort in descending order. It's bad practice to define operator< in the reverse sense within the class, as you can imagine, so you can instead pass a comparison function to std::sort() that reverses the sense of the comparison:

sort(vc.begin(), vc.end(),
    [](const ComplexNumber<float> &f1, const ComplexNumber<float> &f2)
    { return ! (f1 < f2); }
);

These compilation and semantic concerns aside, when I look at the errors you're posting, I see a link error, and it appears that your class is being defined multiple times. This suggests that the include file which defines your class is missing an include guard.

  • Related