3

Basic structure of my code is

class Foo{
  vector<string> _lines;
  vector<int> _n;
  public:
  ...
  bool Comp(int i, int j){
    return something that depends on _lines;
  }
  ...
  void doSomething(){
    std::sort(_n.begin(), _n.end(), Comp);
  }
  ...
};

But I get

error: no matching function for call to 
‘sort(std::vector<unsigned int>::iterator, 
std::vector<unsigned int>::iterator, <unresolved overloaded function type>)

How can I resolve this problem WITHOUT COPYING THE VECTORS? (because these vectors are very very big 17179508 strings to be precise).

Pratik Deoghare
  • 35,497
  • 30
  • 100
  • 146

3 Answers3

4

std::sort expects a binary predicate taking two ints in this case. A member function takes an implicit first parameter, so in all Foo::Comp takes three parameters. You could pass a non-member function, or a static member function, but neither of these would have access to Foo's data members. The simples way is to use std::bind to bind this to the first parameter of the member function:

#include <functional> // for std::bind
#include <vector>
#include <algorithm>

class Foo{
  vector<string> _lines;
  vector<int> _n;
 public:
  ...

  bool Comp(int i, int j){
    return something that depends on _lines;
  }
  ...
  void sort(){
    using namespace std::placeholders;
    std::sort(_n.begin(), _n.end(), std::bind(Comp, this, _1, _2));
  }
  ...
};
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
2

The most obvious initial suggestion is to aggregate your int and string into a struct or std::pair, have a single vector with the aggregate in it, and then sort that vector of aggregates.

But if the two vectors are in fact independent, I would suggest using an external predicate, instead of your Comp method:

struct Comp
{
    explicit Comp(vector<string>& lines) : lines_(lines) { }
    bool operator()(int i, int j) const
    {
        return something that depends on lines_;
    }

    vector<string>& lines_;
};

Then call it:

void doSomething()
{
    std::sort(_n.begin(), _n.end(), Comp(_lines));
}
Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Will this copy create a copy of lines? Because number of string in lines is 17179508. :) – Pratik Deoghare Jun 03 '13 at 16:54
  • @PratikDeoghare no, it will not. But the solution you chose will :-) – juanchopanza Jun 03 '13 at 17:02
  • @Pratik Deoghare No copy of `_lines` will be made. – Mark B Jun 03 '13 at 17:02
  • `std::pair` is probably not a good solution; the elements certainly have more meaningful names than `first` and `second`. But it sounds like he's trying to map `int` to `string` (but I'm not sure); this may be the error to begin with (and perhaps he should drop the vector of `int` completely). But your answer is more or less the right approach if he doesn't. – James Kanze Jun 03 '13 at 17:10
1

What about using your object as the comparator itself. This compiles on gcc 4.6:

class Foo{
  std::vector<std::string> _lines;
  std::vector<int> _n;
  public:

  bool operator()(int i, int j){
    return false;
  }
  void doSomething(){
    std::sort(_n.begin(), _n.end(), *this);
  }
};

Edit:

Turns out that was not such a good idea, copying an object with 17M strings would incur a huge penalty. A nested class, taking a pointer, could be used instead. That would also allow us to have different comparators:

class Foo
{
  std::vector<std::string> _lines;
  std::vector<int> _n;

  class Bar
  {
  public:
      Bar( const Foo * foo ) : _foo( foo ) {}
      bool operator()( int i, int j )
      {
          act on _foo->_lines
      }
  private:
      const Foo * _foo;
  };

public:

  void doSomething(){
    std::sort(_n.begin(), _n.end(), Bar(this));
  }
};
Diego Sánchez
  • 539
  • 2
  • 12