0

I am getting error "no match for operator==in__first. Here is the code:

header file:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>

using namespace std;

struct rankingElement {
   string url;
   int rank;
};

class RankingCreator {
public:
   static const int MAX_QUERY_SIZE = 20;
   RankingCreator();
   virtual ~RankingCreator();
   bool checkPageRank(rankingElement rElement, vector<rankingElement> ranking);
   void insertIntoRanking(rankingElement rElement);
};

And source file :

#include "RankingCreator.h"

bool RankingCreator::checkPageRank(rankingElement rElement,
                                   vector<rankingElement> ranking)
{
   if (ranking.size() < MAX_QUERY_SIZE) {
      // enough space for another page in ranking
      return true;
   } else {
      if (find(ranking.begin(), ranking.end(), rElement.url) != ranking.end()) {
         // url is already in ranking
         return false;
      } else {

      }
   }
   return true;
}

I tried commenting some blocks of code in source file and the line with find() function seems to generate the errors. It is function from class algorithm used to check whether a vector already contains certain element. I found out that it is wrong, because I try to compare struct with string in find function. I can handle that by copying urls from ranking to another vector of string and then use that vector of strings in find function, but when I tried to do that I can't access elements in 'ranking' vector - for instance ranking[i].url doesn't work and I don't know why.. and help would be appreciated.

jweyrich
  • 31,198
  • 5
  • 66
  • 97
koleS
  • 1,263
  • 6
  • 30
  • 46

3 Answers3

4
find(ranking.begin(), ranking.end(), rElement.url)

you are telling find to search for rElement.url (which is of type string) in [ranking.begin(), ranking.end()) (which has elements of type rankingElements). When not explicitely giving std::find a comparison function it tries to use operator== to compare the elements with the searched for elements. So it tries to invoke operator==(rankingElement, string) which obviously doesn't exist. Imo the best way to make something like that work is to use find_if which accepts a predicate:

struct functor  {
    string url;
    functor(const string& str):url(str){}
    bool operator()(const rankingElement& val) { return val.url == this->url; }
};
...
if(find_if(ranking.begin(), ranking.end(), functor(rElement.url)) != ranking.end() )

otherwise you can write an operator==:

bool operator==(const rankingElement& elem, const string& url) 
{ return elem.url == url; }

this will work with find

Grizzly
  • 19,595
  • 4
  • 60
  • 78
3

There is no way the compiler knows how to compare an object of type rankingElement with an object of type string (this is what is happeneing in std::find).

In the std::find you are doing the test:

find(ranking.begin(), ranking.end(), rElement.url)

// Inside this you are iterating through a vector of `rankingElement`
// But the element you ae testing against is: `rElement.url` which is a std::string


// Sort of like this:
ranking[0] == rElement.url
              ^^^^^^^^^^^^  Object of type string
^^^^^^^^^^ Object of type rankingElement

There are a couple of solutions:

  1. Provide an appropriate compare function
    • bool operator==(rankingElement const& lhs, std::string const& rhs)
  2. Use the version of find that allows you to pass a function/functor
    • std::find_if(ranking.begin(), ranking.end(), test_Ranking_against_url)

Important Point:

  1. Never put using namespace std; in the header file.

  2. You can put it using namespace std; the source file.
    But I would even discourage that.
    Prefer to use the long form of all members of std. (ie. std::vector (not vector)).

  3. Pass by reference any large objects (like vectors).
    Use const reference if you don't want the original changed.
    Then you don't incur the cost of a copy operation.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 1 and 2) Well it allows me to use shorter forms - makes life simplier for me and if I put it into the source file, I have to use long form in header file ( but in not so many places in comparison to source file) Why shouldn't I do that? Isn't it made to do that? 3) Thanks. I didn't think about that, good tip for future. Could you explain how it happens that copy operation occurs when I dont' pass a reference to object, but just object ? – koleS Dec 26 '11 at 19:42
  • 1
    1: It pollutes the namespace for other people. If sombody else includes your header file it now dumps everything from standard into the global namespace so you can break other peoples code that is why you should not use it in header files. – Martin York Dec 26 '11 at 20:07
  • 1
    2: It only feels like it makes things simpler. Its only 5 characters. If you must be lazy be explicit about it. `using std::vector;` only brings vector into the global namespace. All good tutorials will tell you not to do this. Ask a question on SO about it. – Martin York Dec 26 '11 at 20:09
  • See: http://stackoverflow.com/q/5469060/14065 and http://stackoverflow.com/q/1452721/14065 – Martin York Dec 26 '11 at 20:14
0

When you use UDF types as the types of STL containers you must before provide valid:

  1. copy ctor;
  2. copy assignment operator ('operator=')
  3. and at least operator== and operator<
nickolay
  • 3,643
  • 3
  • 32
  • 40
  • Then number 3 is wrong. You need to define operator< for sorted containers only and operator == is not required. – Martin York Dec 26 '11 at 20:17