cmp报错: error: reference to non-static member function must be called sort(vec.begin(),vec.end(),c

文章目录

    • 成员函数cmp必须定义为static的原因
    • cmp声明为静态函数static的限制
    • 比较函数cmp需要访问对象状态的例子
    • cmp作为自由函数而不是成员函数的情况

Line 41: Char 33: error: reference to non-static member function must be called
sort(vec.begin(),vec.end(),cmp);
^~~
1 error generated.

cmp报错: error: reference to non-static member function must be called sort(vec.begin(),vec.end(),c_第1张图片

错误信息 “reference to non-static member function must be called” 表示代码尝试将非静态成员函数(在这里是 cmp)当作函数指针使用,但不能这样做,因为非静态成员函数需要一个对象才能被调用

解决这个问题的方式是将 cmp 函数声明为 static

即cmp的函数定义,应该写成:

static bool static cmp(const pair<int,int>&a,const pair<int,int>&b){
	return a.second<b.second;//降序排列
}

本题中,cmp函数必须声明为static是因为它是作为类的成员函数使用的

成员函数默认是与类的实例相关联的,需要通过实例来调用。然而,在使用sort函数时,我们需要传递一个函数指针或函数对象作为比较函数,而成员函数无法直接转换为函数指针

因此,为了让成员函数能够作为比较函数传递给sort,我们需要将其声明为static,这样它就不再与类的实例相关联

静态成员函数不需要对象就能被调用,因此可以被用作函数指针

但是,静态成员函数不能访问类的非静态成员(包括数据和函数),但在本题例子中,cmp 并没有访问其他非静态成员,所以将它声明为 static 不会有问题

  • 除此之外,还应该将cmp函数的参数类型改为const pair&,因为sort函数在处理数据时并不会改变这些数据,所以它更倾向于接受const参数。这也使得cmp函数可以接受临时对象作为参数。

报错代码:

class Solution { 
public:
   //遍历整棵树,用map统计频率
    //这里的遍历顺序不重要,只要全部遍历了就行
    unordered_map<int,int>map;
    vector<int>result;
    void searchTree(TreeNode* root){
        if(root==nullptr){
            return;
        }
        //此处用了前序
        map[root->val]++; //统计元素频率
        searchTree(root->left);
        searchTree(root->right);
    }
    //把统计出来的value进行排序,注意map不能直接对value排序
    //因为map中的数据类型是pair,因此sort的cmp需要重新定义降序排列
    bool cmp(pair<int,int>& a,pair<int,int>& b){
        //注意键值对的pair类型并不是指针,不能用->来访问
        if(a.second>b.second){
            return true;
        }
        else
            return false;
    }
    vector<int> findMode(TreeNode* root) {
        //把map里的数据存在数组里
    	vector<pair<int,int>>vec(map.begin(),map.end());
    	//对数组里的pair.second进行排序
    	sort(vec.begin(),vec.end(),cmp);
        //取最高value的元素key,此时数组vec中已经是value降序排好序的
        result.push_back(vec[0].first);
        //把vec中最高value元素存进result里
        for(int i=1;i<vec.size();i++){
            if(vec[i].second == vec[0].second){
                result.push_back(vec[i].first);
            }
        }
  		return result; 
    }

};

修改结果:

  • 将sort自定义的cmp函数声明为static
class Solution { 
public:
   //遍历整棵树,用map统计频率
    //这里的遍历顺序不重要,只要全部遍历了就行
    unordered_map<int,int>map;
    vector<int>result;
    void searchTree(TreeNode* root){
        if(root==nullptr){
            return;
        }
        //此处用了前序
        map[root->val]++; //统计元素频率
        searchTree(root->left);
        searchTree(root->right);
    }
    //把统计出来的value进行排序,注意map不能直接对value排序
    //因为map中的数据类型是pair,因此sort的cmp需要重新定义降序排列
    bool static cmp(pair<int,int>& a,pair<int,int>& b){
        //注意键值对的pair类型并不是指针,不能用->来访问
        if(a.second>b.second){
            return true;
        }
        else
            return false;
    }
    vector<int> findMode(TreeNode* root) {
        //把map里的数据存在数组里
    	vector<pair<int,int>>vec(map.begin(),map.end());
    	//对数组里的pair.second进行排序
    	sort(vec.begin(),vec.end(),cmp);
        //取最高value的元素key,此时数组vec中已经是value降序排好序的
        result.push_back(vec[0].first);
        //把vec中最高value元素存进result里
        for(int i=1;i<vec.size();i++){
            if(vec[i].second == vec[0].second){
                result.push_back(vec[i].first);
            }
        }
  		return result; 
    }

};

成员函数cmp必须定义为static的原因

如果是在类里作为成员函数定义了cmp,那么这个cmp就需要依赖函数实例才能使用。非静态成员函数不能直接作为普通函数指针来传入sort中

在C++中,非静态成员函数需要一个对象(即隐式的 “this” 指针)来进行调用,因此不能直接作为普通函数指针来使用,否则编译器不知道用哪个对象来调用该成员函数。这就是你在尝试将 cmp 作为参数传递给 sort 函数时发生错误的原因。

另一方面,静态成员函数不依赖于任何对象,因此可以被直接调用,不需要创建对象,就像普通的全局函数一样。因此,静态成员函数可以被直接用作函数指针,也可以作为其他函数的参数

如果想将成员函数作为参数传递给 sort 函数,需要将这个成员函数声明为 static但这只适用于那些不需要访问对象状态(即对象的非静态数据成员)的函数,因为静态成员函数不能访问非静态数据成员。如果你的比较函数需要访问对象状态,你可能需要使用其他方法,如使用函数对象(functor)或lambda表达式。

cmp声明为静态函数static的限制

当我们将比较函数声明为静态成员函数时,它不能直接访问类中的非静态成员变量,也不能访问其他函数体内部的局部变量静态成员函数只能访问静态成员变量和其他静态成员函数

因此**,如果比较函数cmp需要访问对象的状态或其他非静态数据**,需要使用函数对象(functor)或 lambda 表达式。

函数对象可以持有对象的状态作为成员变量,并在函数调用运算符 operator() 中访问这些状态

lambda 表达式可以捕获外部变量,并在函数体中访问这些捕获的变量

这些方法允许在比较函数中访问对象的状态或其他局部变量,并将其作为参数传递给 sort 函数。因此,当需要访问对象状态或其他局部变量时,使用函数对象或 lambda 表达式是更好的选择。

比较函数cmp需要访问对象状态的例子

如果 cmp 函数需要访问对象状态,不能将其声明为静态成员函数,我们可以考虑使用函数对象(functor)或 lambda 表达式来实现。
函数对象(functor): 函数对象是一个类对象,它重载了函数调用运算符 operator()。通过在类中定义一个函数调用运算符重载函数,可以实现具有状态的比较函数。

struct Cmp {
    int state;

    Cmp(int s) : state(s) {}

    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        // 可以访问对象的状态
        if (a.second > b.second + state) {
            return true;
        } else {
            return false;
        }
    }
};

// 使用函数对象进行排序
Cmp cmpObject(10);
sort(vec.begin(), vec.end(), cmpObject);

Lambda 表达式: Lambda 表达式是一种匿名函数的方式,可以在函数中直接定义比较函数,并捕获外部的对象状态。

int state = 10;

// 使用 lambda 表达式进行排序
sort(vec.begin(), vec.end(), [state](const pair<int, int>& a, const pair<int, int>& b) {
    // 可以访问外部对象的状态
    if (a.second > b.second + state) {
        return true;
    } else {
        return false;
    }
});

在上述示例中,函数对象 Cmp 或 lambda 表达式都可以访问外部对象的状态,并将其作为比较函数传递给 sort 函数。这样就可以根据需要在比较函数中访问对象状态,并根据状态进行排序。

cmp作为自由函数而不是成员函数的情况

如果cmp函数是作为普通的自由函数声明的,而不是类的成员函数,那么就不需要声明为static。

自由函数不依赖于任何特定的类实例,因此可以直接传递给sort函数作为函数指针

例子:

struct Student {
    string name;
    int score;
};

bool cmp(const Student& a, const Student& b) {
    return a.score < b.score;
}

vector<Student> students;
// fill students...
sort(students.begin(), students.end(), cmp);

你可能感兴趣的:(算法,c++,leetcode)