首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

带有自定义比较函数结果的std::sort函数错误:必须调用对非静态成员函数的引用

在使用std::sort函数时,如果传递的是一个自定义的比较函数,并且这个比较函数是一个类的非静态成员函数,那么会出现错误:“必须调用对非静态成员函数的引用”。这是因为非静态成员函数需要一个隐含的this指针来指向调用该成员函数的对象实例。

基础概念

  • 非静态成员函数:属于类的实例,需要通过对象来调用,有一个隐含的this指针。
  • std::sort:C++标准库中的排序算法,可以对范围内的元素进行排序。

问题原因

当传递一个非静态成员函数作为比较函数时,std::sort无法正确地调用这个函数,因为它不知道如何传递this指针。

解决方法

  1. 使用静态成员函数:如果可能,将比较函数改为静态成员函数。
  2. 使用Lambda表达式:Lambda表达式可以捕获外部变量,包括对象的引用。
  3. 使用函数对象(Functor):定义一个函数对象,并在其中实现比较逻辑。

示例代码

方法一:使用Lambda表达式

代码语言:txt
复制
#include <iostream>
#include <vector>
#include <algorithm>

class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
};

int main() {
    std::vector<MyClass> vec = {MyClass(3), MyClass(1), MyClass(2)};

    std::sort(vec.begin(), vec.end(), [](const MyClass& a, const MyClass& b) {
        return a.value < b.value;
    });

    for (const auto& obj : vec) {
        std::cout << obj.value << " ";
    }
    return 0;
}

方法二:使用函数对象

代码语言:txt
复制
#include <iostream>
#include <vector>
#include <algorithm>

class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
};

struct Compare {
    bool operator()(const MyClass& a, const MyClass& b) const {
        return a.value < b.value;
    }
};

int main() {
    std::vector<MyClass> vec = {MyClass(3), MyClass(1), MyClass(2)};

    std::sort(vec.begin(), vec.end(), Compare());

    for (const auto& obj : vec) {
        std::cout << obj.value << " ";
    }
    return 0;
}

参考链接

通过上述方法,可以解决传递非静态成员函数给std::sort时出现的错误。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

2021-04-14 quickjs调用静态成员函数

有这样一个需求:多线程条件下执行交易,每个交易都会通过quickjs回调c++代码函数,而这个函数使用数据又来自于当前交易 首先不考虑用全局变量来保存交易数据,因为js回调c函数时候我们无法在回调函数中区分当前属于哪个交易...一个简单思路是c代码创建交易类,然后把类函数传递给quickjs,然后在js中调用这个类函数,但是这个实现不了,因为quickjs没有注入静态成员函数接口,其原因文章static成员函数通过类名...::来调用,空指针调用成员方法不出错!...讲解比较清楚 换个思路,我们先用js创建这个类,然后调用eval把类数据传递给它,这样调用这个类静态成员函数时候就可以正确访问到数据了,我们直接修改文件example.cpp 具体实现如下...return 1; } } 执行结果如下: Hello, world 5.500000 Hello, world 3.000000 这样一来,每个交易数据都是独立在quickjs中执行,实现了并行处理目的

97920

C++11 Lambda 表达式

比如C++STL中很多算法函数模板需要传入谓词(predicate)来作为判断条件,如排序算法sort。谓词就是一个可调用表达式,其返回结果是一个能用作条件值。...接受谓词算法输入序列中元素调用谓词,因此元素类型必须能转换为谓词参数类型。...如下面使用sort()传入比较函数shorter()(这里比较函数shorter()就是谓词)将字符串按长度由短至长排列。...按照规则,一个 const 成员函数是不能在函数体内改变静态成员变量值。...lambda函数是通过仿函数来实现,捕捉到变量相当于是仿函数类中成员变量,而lambda函数相当于是成员函数,const成员函数自然不能修改普通成员变量; (2)使用引用方式捕获变量在常量成员函数中值被更改则不会导致错误

2K41
  • C++11 Lambda表达式

    比如C++STL中很多算法函数模板需要传入谓词(predicate)来作为判断条件,如排序算法sort。谓词就是一个可调用表达式,其返回结果是一个能用作条件值。...接受谓词算法输入序列中元素调用谓词,因此元素类型必须能转换为谓词参数类型。...如下面使用sort()传入比较函数shorter()(这里比较函数shorter()就是谓词)将字符串按长度由短至长排列。...函数,按照规则,一个const成员函数是不能在函数体内改变静态成员变量值。...lambda函数是通过仿函数来实现,捕捉到变量相当于是仿函数类中成员变量,而lambda函数相当于是成员函数,const成员函数自然不能修改普通成员变量; (2)使用引用方式捕获变量在常量成员函数中值被更改则不会导致错误

    1.3K31

    【Example】C++ 回调函数std::function 与 std::bind

    举个最经典例子就是 std::sort,当你需要给一个存储有自定义结构体 vector 进行排序时,编译器是无法知道如何自定义结构体进行排序。...std::sort 自定义 struct 进行排序操作。...作用是C++中调用对象进行包装,例如普通函数成员函数、模板函数静态函数、lambda表达式等。 它最基本作用是,简化调用复杂程度,统一调用方式。...当用作类成员函数绑定时,第一个参数仍然是作为类成员调用对象引用,第二个参数则是对象指针,而第三个参数开始对应可调用对象参数表。...<< "c Value: " << c << std::endl; return EXIT_SUCCESS; } std::bind 额外注解: 1,调用指向静态成员函数指针或指向静态数据成员指针时

    4.8K30

    C++为什么有参数依赖查找(ADL)?

    静态数据成员或枚举器),这时会发生名称冲突。...这种名称可以指向: 类成员(包括静态静态函数、类型、模板等) 命名空间成员(包括另一个命名空间) 通常在命名空间作用域查找。...这允许引用被局部声明隐藏名称。在对::右侧名称进行查找之前,必须先完成对左侧名称查找。查找可能是限定限定,取决于该名称左侧是否有另一个::。...:首先会判断是否执行ADL:如果通常未限定查找结果中包含类成员声明、块作用域中函数声明(using声明)或任何函数函数模板声明,则不执行ADL。...然后每个参数进行类型检查:对于函数调用表达式中每个参数,会检查其类型以确定将添加到查找中相关命名空间和类(具体不同类型对应命名空间规则比较复杂,详见cppreference)接着关联集合:基于参数类型

    10110

    C++相关基础知识总结笔记

    静态成员变量可以是 const 类型。const 静态成员变量在类外部初始化时必须提供初始值,并且一旦初始化就不能改变。 静态成员变量是否可以是引用类型? 不可以。静态成员变量不能是引用类型。...引用必须在声明时初始化,并且不能重新绑定。因此,引用不能作为静态成员变量。 静态成员变量是否可以在构造函数中初始化? 不可以。静态成员变量在构造函数之前就已经初始化了。...构造函数用于初始化对象静态成员变量,而静态成员变量在类所有对象创建之前就已经存在。 静态成员变量生命周期是怎样静态成员变量生命周期从程序启动到程序结束。...静态成员函数相关 静态成员函数特点 没有this指针:静态成员函数不隐式地接收this指针,因此它不能直接访问类静态成员变量或调用静态成员函数。...(无参,函数体为空) 3.默认拷贝构造函数类中非静态成员属性简单值拷贝 如果用户定义拷贝构造函数,c++不会再提供任何默认构造函数 如果用户定义了普通构造(拷贝),c++不在提供默认无参构造

    18520

    C++11第三弹:lambda表达式 | 新类功能 | 模板可变参数

    lambda表达式 C++98中一个例子 在C++98中,如果想要对一个数据集合中元素进行排序,可以使用std::sort方法。...,排出来结果是升序 std::sort(array, array+sizeof(array)/sizeof(array[0])); // 如果需要降序,需要改变元素比较规则 std::sort(array...在块作用域以外lambda函数捕捉列表必须为空。 在块作用域中lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者局部变量都会导致编译报错。...默认生成移动构造函数,(1)对于内置类型成员会执行逐成员按字节拷贝,(2)自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。...默认生成移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。

    8110

    大学C++课程提炼概括【C++笔记】

    //不可变,不同对象之间不共享 //只能通过构造函数参数初始化表初始化(例子如下) //可以在const对象内创建 //静态常数据成员是在所有函数之外初始化 //常/非常成员函数都可以调用常数据成员...//可以引用任意数据成员 //可以在const对象内创建,如果存在const导致重构的话,const不会被const对象优先调用 //主要是在常对象中使用,常对象能使用函数只有它了 /...public: static void show() { cout<<d<<endl;//静态成员函数 原则是只调用静态变量 //非要调用静态变量...cout<<T::d;//也可以直接类引用 } //全局变量周期 //this指针指向类对象本身,而static静态成员函数不依赖对象调用,它不与任何对象相联系,故不会使用this指针。...// 编译系统发现“+”左侧d2是double型,右侧c1是 complex对象,如果没有“+”重载,就会检测有无类型转换函数结果发现double重载函数,就调用函数,将complex对象

    36970

    【笔记】《深入理解C++11》(上)

    其他构造函数通过带有默认值委派构造来调用这个目标构造函数 千万小心环形委派, 会导致编译错误 委派构造函数使得构造函数模板编程也成为一种可能, 通过让模板构造函数成为委派构造函数, 我们可以很容易地接受多种不同类型参数进行相同底层初始化...(为了保证成员摆放顺序一致) 派生类有静态成员时, 只有一个仅有静态成员基类(为了保证基类能被直接折叠, 因为C没有继承关系) 基类有静态成员时, 派生类没有静态成员(为了派生类折叠, 因为C...没有继承关系) 类中第一个静态成员类型要与基类不同(为了类指针能直接指向第一个成员) 没有虚函数和虚基类 所有静态成员都满足POD布局(递归定义) 之所以C++11引入POD概念是为了保证我们可以安全地用...最终可以用is_pod::value直接判断是否POD 受限联合 C++11后, 任何引用类型都可以成为union成员(包括函数), 因此称为受限联合 不允许静态成员变量存在 union一些默认函数将被删除...而且由于其本质是常量数值原因, enum成员总是可以被隐式转换为整型, 这很容易导致比较两个不同枚举名称时出现错误结果 C++11之前会通过类结构将枚举封装, 并建立新转换和比较函数覆盖原先操作

    1.9K20

    读完某C++神作,我只记下了100句话

    const对象,指针引用只能调用常量成员函数。 没有前缀成员都被假定为this在调用。 默认构造函数按变量初始化规则初始化类中所有成员【内置类型作为局部变量时不初始化】。...static成员函数没有this形参,可直接访问类static成员,不能使用static成员静态数据成员属于一个类,而不属于类各个对象。静态成员函数在所有对象建立之前或删除之后仍然使用。...构造函数如果是explicit必须严格按照定义使用构造函数,否则可以存在隐式转换。 引用形参将复制实参值,引用return将复制return东西。...派生类指针静态类型和动态类型不一致时【基类指针指向派生类是时】,为保证删除指针调用合适析构函数【多态】,基类析构必须为virtual。...关联容器构造函数是我们能够提供比较函数名字:std::multiset items(compare【比较函数】); template <typename

    1.4K20

    C++20新特性个人总结

    ,用constexpr函数constinit变量进行初始化 constinit const char *str3 = hahah; // 编译错误,用非常量表达式constinit变量进行初始化...return 0; }  ②模板参数成员函数调用  因为模板参数是处于编译期计算,因此,作为调用用于自定义类型模板参数成员函数时,这些成员必须是constexpr修饰。 ...  简单地说,就是相当于默认有一个有全部静态数据成员构造函数。...指向成员指针类型,且引用相同成员,或者都是空成员指针值;  ⑦引用类型,且引用相同对象或函数;  ⑧数组类型,对应元素满足模板参数等效;  ⑨共用体类型,或者都没有活动成员,或者都具有相同活动成员...(没有静态数据成员)有效。

    1.9K50

    基础知识_Cpp

    修饰类内成员,堆区分配内存;程序运行时就被初始化,直到程序结束;成员归属于类,被所有对象共享;可以通过”类名::静态成员”或”对象.静态成员”访问 修饰类内函数,只能访问类内静态成员调用类内静态函数,...但是普通函数可以访问静态成员静态函数;可以通过类名调用或对象调用。...(使用delete会报错,因为delete对象指针,会调用对象析构函数,而析构函数类外不可访问)这种使用方式比较怪异。...堆排序是指在当递归深度达到logn时(即快排有递归恶化倾向出现),调用堆排序序列进行排序。 第二步插入排序也不是标准插入排序,也是将序列分段进行插入排序,节省了一次排序过程中比较操作。...sort实现中有很多技巧排序进行了优化,全是为了提高效率,其最坏情况时间复杂度也是nlogn。包括使用while循环减少一半快排函数递归调用、插入排序分段、使用堆排序优化递归层数等。

    2K30

    C++ 新特性学习(四) — Bind和Function

    接下来一个一个来 Bind 可用于绑定函数成员函数函数对象、成员变量 这是老标准中std::bind1st和std::bind2nd增强版,这两个函数只能且必须绑定一个带有两个参数,并且只能且必须传入一个自定义参数...所以为了性能上考虑,建议传入类型为引用或指针,避免结构复制 另外,除了普通函数外,std::bind也支持成员函数,但是和普通函数不同,成员函数绑定第二个参数必须函数实例。...(特别注意是绑定类成员时遗漏类实例) 绑定参数类型不匹配将会在调用时编译错误 占位符不匹配将会在调用时编译错误 绑定对象必须函数成员函数指针 绑定对象默认为c++函数且不支持变长参数函数,...std::function同样支持函数成员函数函数变量和函数结构。 std::function和std::bind配合使用时是把std::bind返回结果作为函数对象使用。...复制性能: 取决于所关联函数函数对象,建议采用函数函数对象引用传给std::function来提高复制性能 执行性能: 一个正常内联编译器而言,将会通过函数指针执行函数调用

    2.4K10

    C++11

    默认生成移动构造函数,对于内置类 型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造, 如果实现了就调用移动构造,没有实现就调用拷贝构造。...默认生成移动构造函数,对于内 置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋 值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。...lambda表达式 我们在比较自定义大小时候,需要自己定义一个类来进行比较(也叫仿函数)。...捕捉列表不允许变量重复传递,否则就会导致编译错误。 比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复 d. 在块作用域以外lambda函数捕捉列表必须为空。 e....= Plus::plusi; cout << fc2(1, 1) << endl; //静态成员函数 //静态成员函数需要对象指针或者对象进行调用 /*Plus plus; function

    11510

    C++(STL):02---tuple容器

    pair接受两个成员,tuple接受任意数目的成员 当我们希望将一些数据组合成单一象时,tuple非常有用 tuple实现 TR1标准时(C++11之前),tuple最多带有10个实参,因此tuple...但是tuple容器成员数目是不限制,因此我们必须使用get标准库函数模板来访问tuple中元素 为了使用get,我们必须指定一个显式模板实参,用来指出要访问第几个成员成员索引从0开始 get返回指定成员引用...对于tuple可以使用其成员函数来处理元素,因此必须在编译期知道你打算处理元素索引值。...,则它们比较结果取决于第一个不相等元素比较结果 tuple与STL容器比较规则类似,但是: 只有两个tuple具有相同数量成员时才可以进行比较 为了使用相等或不等运算符,每对成员相等或不等运算符都必须是合法...类似的为了使用关系运算符,每对成员使用关系运算符也必须是合法 例如: std::tuple duo("1", "2"); std::tuple

    1.2K20

    C++:31---对象引用和赋值

    我们可以将一个左值引用绑定到这类表达式结果上 右值引用: 则与左值引用相反,我们可以将一个右值引用到上面所述表达式上,但是不能将一个右值引用直接绑定到一个左值上 返回引用类型函数,连同算术、关系...但是注意,我们上面介绍move()函数,可以显式地将一个左值转换成对应右值引用类型,因此参数可能是move()调用返回结果,因此我们需要在函数运行前检测自我赋值 四、移动后,对象仍是有效、可析构...(const std::string& s){chk_n_alloc(); //自定义函数,用来检测是否空间足够 //在first_free指向元素中构造s一个副本,此处construct会调用string...,引用限定符只能作用于(static)成员函数,且在声明和定义时都需要 引用限定符可以和const一起使用,且const必须在限定符前面。...const类型右值(因为其带有const,见下面的重载介绍)Foo sorted()const & {Foo ret(*this); //拷贝一个副本std::sort(ret.data.begin(

    1.7K10

    《C++Primer》第十九章

    成员指针是指可以指向类静态成员指针。...,因此之前对于pdata使用必须位于Screen类成员或友元内部,否则程序将发生错误。...&Screen::get_cursor; 指向成员函数指针也需要指定目标函数返回类型和形参列表 如果成员函数是const成员引用成员,我们必须将const限定符或者引用限定符包含进来 如果成员存在重载问题...将成员函数用作可调用对象 要想通过有一个指向成员函数指针进行函数调用必须首先利用.*或者->*运算符将该指针绑定到特定对象上。...局部类成员必须完整定义在类内部,所以成员函数复杂性不能太高,一般只有几行代码 在局部类中不允许声明静态数据成员 1.

    1.3K10

    C++初阶

    内置类型和自定义类型在析构中 关于编译器自动生成析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成默认析构函数自定类型成员调用析构函数。...类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 4. 静态成员函数没有隐藏this指针,不能访问任何静态成员 5....静态成员变量初始化,必须在类外定义(可已突破私有) 静态成员变量一般配套静态成员函数 静态可以调用静态 静态成员函数不能访问静态成员变量,因为无this指针 全局变量缺点,任何地方都可以进行修改...main之前就初始化 局部相反 静态成员调用多次,只创建一次和内联函数作用类似 静态成员变量存储在静态区,生命周期是全局 静态成员初始化必须在类外,定义时可以突破私有 静态成员函数不能访问静态成员变量...this指针,只有静态成员函数才有,且为隐藏指针 B.静态成员函数第一个参数就是隐藏this指针 C.this指针在静态成员函数里面,对象不存在,故错误 D.单纯this赋空是不可以

    1600

    C++初阶大全

    内置类型和自定义类型在析构中 关于编译器自动生成析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成默认析构函数自定类型成员调用析构函数。...类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 4. 静态成员函数没有隐藏this指针,不能访问任何静态成员 5....静态成员变量初始化,必须在类外定义(可已突破私有) 静态成员变量一般配套静态成员函数 静态可以调用静态 静态成员函数不能访问静态成员变量,因为无this指针 全局变量缺点,任何地方都可以进行修改...main之前就初始化 局部相反 静态成员调用多次,只创建一次和内联函数作用类似 静态成员变量存储在静态区,生命周期是全局 静态成员初始化必须在类外,定义时可以突破私有 静态成员函数不能访问静态成员变量...this指针,只有静态成员函数才有,且为隐藏指针 B.静态成员函数第一个参数就是隐藏this指针 C.this指针在静态成员函数里面,对象不存在,故错误 D.单纯this赋空是不可以

    1000

    const成员函数一定是线程安全吗?

    */ //实例2:C++11新规定:基类和派生类中函数引用修饰词必须完全相同 //这个概念是为了实现限制成员函数仅仅用于左值或右值,带有引用修饰词成员函数,不必是虚函数 class Widget{...//以上改写:需要满足 /** 1,如果基类中函数带有引用修饰词,则派生类要对该函数进行改写版本必须带有完全相同引用修饰词 2,如果不这样,那么这些声明了函数在派生类依然存在,只是不好改写基类中任何函数...//函数是否会发射异常这一行为,是客户方关注核心,调用方可以查询函数 noexcept状态,而查询结果可能会影响调用代码异常安全性或运行效率 //因此可以理解:函数是否带有 noexcept声明,...//宗旨:多个线程同时调用带有 const 得成员函数,如何保证线程安全性 //const成员函数就一定是线程安全吗?.../** 注意两点: 1, 类中存在指针,会出现深拷贝和浅拷贝问题,此时必须自定义拷贝构造函数实现深拷贝 2, 拷贝构造函数第一个参数必须是该类一个引用

    1.1K20
    领券