3

This is NOT a duplicate question It differs here as the comparison function has a dependancy on the main class.

All my logic is in a class. I have a map nodeCnt which can be looked up upon getCnt() . I am figuring out for how to have a custom comparison myCmp for my priority queue pq which will do comparison based on the map.

The following snippet does not work. And having auto cmp as described in reference docs cannot be done as Class cannot have such declarations for comparison function.

Class AllLogic {

 private:
   std::map<int, int> nodeCnt;

   // This is my confusing part
   std::priority_queue<int, std::vector<int>, decltype(&myCmp)> pq(&myCmp);

 public:

   int getCnt(int val) {
     if (nodeCnt.find(val) != nodeCnt.end())
         return nodeCnt[val];  
      return 0;
    }

  bool myCmp(int left, int right) {
     return getCnt(left) < getCnt(right);
  } 
};
visweshn92
  • 301
  • 1
  • 3
  • 13
  • Hi @kfsone. This is not duplicate. This is 'slightly' different from existing ones. – visweshn92 Oct 01 '16 at 21:22
  • The comparison function has a dependancy on the main class. Unlike the related duplicate link you have posted. – visweshn92 Oct 01 '16 at 21:24
  • Don't say "does not work" here on stackoverflow, but just describe the problem... –  Oct 01 '16 at 21:41
  • 1
    `myCmp` is a member function so its use would require an instance off of which to call it, `this` is not implied. To remedy this, use `function` and a lambda: `priority_queue<..., std::function pq([this](int a,int b){return this->myCmp(a,b);});` – David G Oct 01 '16 at 21:42

2 Answers2

4

Make a struct like this:

// forward declare your class, because the comparator will use it
class AllLogic;

struct MyCompareT
{
    AllLogic* object;
    bool operator()(int left, int right) const;
};

// after AllLogic has been defined
bool MyCompareT::operator()(int left, int right) const {
    return object->myCmp(left, right);
}

And your priority_queue can be defined as:

std::priority_queue<int, std::vector<int>, MyCompareT> pq;

And initialized in the constructor like this:

AllLogic() :pq(MyCompareT{this}) {}
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
1

You can rework the code a bit to the following (note: the following is c++11):

#include <map>
#include <queue>

The comparison functor takes a reference to the map, and uses it to compare:

struct myCmp {
    explicit myCmp(std::map<int, int> &nodeCnt) : nodeCnt_{&nodeCnt} {}

    bool operator()(int lhs, int rhs) const {
        auto lhs_it = nodeCnt_->find(lhs);
        auto rhs_it = nodeCnt_->find(rhs);
        auto lhs_val = lhs_it == nodeCnt_->end()? 0: lhs_it->second;
        auto rhs_val = rhs_it == nodeCnt_->end()? 0: rhs_it->second;
        return lhs_val < rhs_val; 
    }

private:
   std::map<int, int> *nodeCnt_;
};

The class sets the map, then the comparison functor, then the queue; each one uses the previous one:

class AllLogic {
private:
   std::map<int, int> nodeCnt;
   myCmp myCmp_{nodeCnt};
   std::priority_queue<int, std::vector<int>, myCmp> pq{myCmp_};
};

int main(){}
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • Can u add little comment on how the operator() works? I notice that nodeCnt_ is a copy of nodeCnt. But how are updates to nodeCnt getting reflected in nodeCnt_ – visweshn92 Oct 01 '16 at 21:49
  • 1
    @visweshn92 It takes it by reference, and stores it by pointer. So any changes to the original object, are automatically present here too. It's actually *not* a copy. – Ami Tavory Oct 01 '16 at 21:52