Hanito
Hanito

Reputation: 3

Template function for container and type to compare vector of pointers

I want to compare 2 containers (vectors or sets) of pointers. I am trying to have a function that is also independent of the type.

First I tried the following. But the problem is that it is always returning 0 even tho both containers have objects with same content.

  template<typename Container >
    bool isEqual(const Container &lhs,const Container &rhs ) {
        bool ok = equal(begin(lhs), end(lhs), begin(rhs));

        return ok;
    }

Then I tried to use the following function:

 template<typename T , typename Container >
    bool isEqual(const Container &lhs,const Container &rhs ) {
        bool ok = equal(begin(lhs), end(lhs), begin(rhs),
                    [](const T* lhs, const T* rhs){ return *lhs == * rhs; });

        return ok;
    }

but the problem is that it is producing the following errors and I don't understand why.

 In function 'int main()':
31:31: error: no matching function for call to 'isEqual(std::vector<Point*>&, std::vector<Point*>&)'
31:31: note: candidate is:
19:6: note: template<class T, class Container> bool isEqual(const Container&, const Container&)
19:6: note:   template argument deduction/substitution failed:
31:31: note:   couldn't deduce template parameter 'T'
36:31: error: no matching function for call to 'isEqual(std::set<Point*>&, std::set<Point*>&)'
36:31: note: candidate is:
19:6: note: template<class T, class Container> bool isEqual(const Container&, const Container&)
19:6: note:   template argument deduction/substitution failed:
36:31: note:   couldn't deduce template parameter 'T'

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

class Point {
    public:
    Point(int x, int y):_x(x),_y(y) {}
    private:
     int _x;
     int _y;
};

template<typename T , typename Container >
bool isEqual(const Container &lhs,const Container &rhs ) {
    bool ok = equal(begin(lhs), end(lhs), begin(rhs),
                [](const T* lhs, const T* rhs){ return *lhs == * rhs; });

    return ok;
}

int main()
{
    std::vector<Point *> v1 = {new Point(10,10)};
    std::vector<Point *> v2  = {new Point(10,10)};

    std::cout << isEqual(v1,v2) << std::endl;

    std::set<Point *> s1 = {new Point(10,10)};
    std::set<Point *> s2  = {new Point(10,10)};

    std::cout << isEqual(s1,s2) << std::endl;

    return 0;
} 

Upvotes: 0

Views: 266

Answers (2)

Manish
Manish

Reputation: 738

Since you have asked "I want to compare 2 containers (vectors or sets) of pointers." I will suggest you to use the following form of std::equal for element to element comparison, as your mentioned form only compares it till the length of the first container.

template<typename Container >
bool isEqual(const Container &lhs,const Container &rhs ) {
bool ok = equal(begin(lhs), end(lhs), begin(rhs), end(rhs),
    [](const auto* lhs, const auto* rhs){ return *lhs == * rhs; });

return ok;
}

That being said, you will anyways have to define == operator for the comparison that you are performing in the end. As mentioned by the above answer too.

Upvotes: 0

NathanOliver
NathanOliver

Reputation: 180490

The problem with

template<typename T , typename Container >
bool isEqual(const Container &lhs,const Container &rhs ) {
    bool ok = equal(begin(lhs), end(lhs), begin(rhs),
                [](const T* lhs, const T* rhs){ return *lhs == * rhs; });

    return ok;
}

is that there is no way to deduce what T is. Since it is not used in the function parameters the compiler doesn't know what it should be so you have to tell it when you call the function. That said, you don't actually need T. We can rewrite the lambda to use auto parameters which will turn the function call operator of the lambda into a template. That changes the code to be

template<typename Container >
bool isEqual(const Container &lhs,const Container &rhs ) {
    bool ok = equal(begin(lhs), end(lhs), begin(rhs),
                [](const auto* lhs, const auto* rhs){ return *lhs == * rhs; });

    return ok;
}

Which brings you to your next issue. *lhs == * rhs compares the objets using operator ==. You haven't defined a operator == for Point so it wont compile. You need to change Point to something like

class Point {
    public:
    Point(int x, int y):_x(x),_y(y) {}
    bool operator ==(const Point& rhs) { return std::tie(_x, _y) == std::tie(rhs._x, rhs._y); }
    private:
     int _x;
     int _y;
};

So they can actually be compared.


Do note that if you use a std::vector<Point> instead of a std::vector<Point *> then std::vector provides it's own operator == and you can compare two std::vector<Point> just by doing

std::vector<Point> v1;
// fill v1
std::vector<Point> v2
// fill v2
if (v1 == v2)
    // vectors are equal.

There doesn't look to be any reason you to have a std::vector<Point *> so I recommend this solution.

Upvotes: 1

Related Questions