问题引入
有一个类 A,A 的某个成员函数需要对 A 的某些变量进行 std::sort
,同时要调用 A 的另一个成员函数作为比较器。如代码所示:
struct A {
vector<int> pos = {0, 4, 2, 5, 3};
bool cmp(int x, int y) { return pos[x] < pos[y]; }
void demo() {
vector<int> a = {2, 3, 1, 0, 4};
sort(a.begin(), a.end(), cmp);
for (int x : a) printf("%d\n", x);
}
};
希望以 A::cmp
作为比较器对 vector<int> a
排序。
编译错误:(关键的一段)
error: must use '.*' or '->*' to call pointer-to-member function in '((__gnu_cxx::__ops::_Iter_comp_iter<bool (A::*)(int, int)>*)this)->__gnu_cxx::__ops::_Iter_comp_iter<bool (A::*)(int, int)>::_M_comp (...)', e.g. '(... ->* ((__gnu_cxx::__ops::_Iter_comp_iter<bool (A::*)(int, int)>*)this)->__gnu_cxx::__ops::_Iter_comp_iter<bool (A::*)(int, int)>::_M_comp) (...)'
{ return bool(_M_comp(*__it1, *__it2)); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
解决方案一:lambda functions
struct B {
vector<int> pos = {0, 4, 2, 5, 3};
void demo() {
vector<int> a = {2, 3, 1, 0, 4};
sort(a.begin(), a.end(), [&](int x, int y) { return pos[x] < pos[y]; });
for (int x : a) printf("%d ", x);
}
};
直接使用 lambda 函数,引用捕获 this->pos
进行访问。关于 lambda 函数的更多说明参见 https://zh.cppreference.com/w/cpp/language/lambda。
解决方案二:static members
struct C {
vector<int> pos = {0, 4, 2, 5, 3};
static bool cmp(int x, int y) { return x < y; }
void demo() {
vector<int> a = {2, 3, 1, 0, 4};
sort(a.begin(), a.end(), cmp);
for (int x : a) printf("%d ", x);
}
};
将 bool cmp(int, int)
声明为 static
,也就是静态成员函数。静态成员函数不和任意一个对象绑定,它是静态的,它是静态区域的函数,可以使用 A::cmp
或者 a.cmp
调用。静态成员函数不能访问类中的变量。关于 static 的更多说明参见 https://zh.cppreference.com/w/cpp/language/static。
解决方案三:std::bind
struct D {
vector<int> pos = {0, 4, 2, 5, 3};
bool cmp(int x, int y) { return pos[x] < pos[y]; }
void demo() {
using namespace placeholders;
vector<int> a = {2, 3, 1, 5, 4};
sort(a.begin(), a.end(), bind(&D::cmp, *this, _1, _2));
for (int x : a) printf("%d ", x);
}
};
关键问题在于,成员函数 A::cmp
的形参列表看似只有两个 bool cmp(int x, int y)
,但是因为它是成员函数,需要带着自己绑定的对象调用,它实际上是 bool A::cmp(/*const*/ A&, int x, int y)
。那么使用 std::bind,将自己绑定到第一个参数的位置,大概的使用方法见上。这种方法可以使 cmp
有 cv 限定。关于 std::bind 的更多说明见 https://zh.cppreference.com/w/cpp/utility/functional/bind。