0
#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
using namespace std;

class C
{
public:
    vector<int> CSort();
    bool Func(int x, int y);
private:
    vector<int> data;
};

vector<int> C::CSort()
{
    vector<int> result(data.size(), 0);
    iota(result.begin(), result.end(), 0);
    sort(result.begin(), result.end(), Func);
    return result;
}

bool C::Func(int x, int y)
{
    return (data[x] > data[y]);
}

In my class C defined as above, I would like to get an order vector of data with std::sort using the member function Func. The result was an error

'C::Func': non-standard syntax; use '&' to create a pointer to member

I believe this has something to do with Why doesn't reference-to-member exist in C++.

However, I cannot come up a proper way to reference this function in std::sort. How can I implement it correctly?

Community
  • 1
  • 1
  • @ArchbishopOfBanterbury You were correct, and initializing a descending order vector is a good reminder, thanks a lot ;) – Yizhou Wei Dec 24 '16 at 14:45
  • As a side note, `std::sort(result, &C::Func);` should work out-of-the-box with the upcoming Ranges TS. – Morwenn Dec 24 '16 at 15:14

3 Answers3

1

A lambda will work:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
using namespace std;

class C
{
public:
    vector<int> CSort();
    bool Func(int x, int y);
private:
    vector<int> data;
};

vector<int> C::CSort()
{
    vector<int> result(data.size(), 0);
    iota(data.begin(), data.end(), 0);
    sort(data.begin(), data.end(), [this](auto& l, auto& r) {return Func(l, r); });
    return result;
}

bool C::Func(int x, int y)
{
    return (data[x] > data[y]);
}

int main()
{
    C c;
}

or bind:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <functional>

using namespace std;

class C
{
public:
    vector<int> CSort();
    bool Func(int x, int y);
private:
    vector<int> data;
};

vector<int> C::CSort()
{
    vector<int> result(data.size(), 0);
    iota(data.begin(), data.end(), 0);
    sort(data.begin(), data.end(), std::bind(&C::Func,this,std::placeholders::_1,std::placeholders::_2));
    return result;
}

bool C::Func(int x, int y)
{
    return (data[x] > data[y]);
}

int main()
{
    C c;
}
wally
  • 10,717
  • 5
  • 39
  • 72
  • 1
    don't use `std::bind` for member functions until after you've grabbed the function via [`std::mem_fn`](http://en.cppreference.com/w/cpp/utility/functional/mem_fn) but to be honest both are unnecessary in C++14 – Mgetz Dec 24 '16 at 14:44
  • @Mgetz Interesting. But how would that work? Don't we need to bind to a specific instance in this example? – wally Dec 24 '16 at 14:57
  • 1
    We do, but in C++ the safe way to grab a reference a member function is to use `std::mem_fn`, it's also the easy way. The returned function object is guaranteed to have the `this` parameter as the first parameter. Whereas a pointer-to-member function like you're using is not as that's an ABI specific implementation detail. – Mgetz Dec 24 '16 at 15:03
  • 1
    No, it's neither particularly safe nor particularly easy. The best way to go is just to use a lambda. – Puppy Dec 24 '16 at 15:09
  • @Mgetz do you mean something like `std::bind(std::mem_fn(&C::Func),this,std::placeholders::_1,std::placeholders::_2))`? – wally Dec 24 '16 at 15:22
1

You've got a couple of options:

If you don't have access to C++11 you can go old school and implement your own comparator that preserves state:

class C
{
    friend struct MyComp;
public:
    vector<int> CSort();
private:
    vector<int> data;
};

struct MyComp
{
    C* data;
    MyComp(C* data) : data(data) {}
    bool operator()(int x, int y)
    {
        return data->data[x] > data->data[y];
    }
};

vector<int> C::CSort()
{
    vector<int> result(data.size(), 0);
    iota(data.begin(), data.end(), 0);
    sort(data.begin(), data.end(), MyComp(this));
    return result;
}

However, if you do, you can just use a lambda:

vector<int> C::CSort()
{
    vector<int> result(data.size(), 0);
    iota(data.begin(), data.end(), 0);
    sort(data.begin(), data.end(), [this] (int x, int y) {
        return (data[x] > data[y]);
    });
    return result;
}
Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
0

Quick and dirty way: Move Func outside the class.

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
using namespace std;

class C
{
 public:
  vector<int> CSort();
 private:
  vector<int> data;
};

bool Func(int x, int y) {
  return x > y;
}

vector<int> C::CSort()
{
  vector<int> result(data.size(), 0);
  // iota(data.begin(), data.end(), 0);
  sort(data.begin(), data.end(), Func);
  return result;
}
gongzhitaao
  • 6,566
  • 3
  • 36
  • 44