[STL]sort和priority_queue中使用仿函数时的不同

8 篇文章 0 订阅
一、问题提出
1.自定义比较函数的sort

我们可以使用自定义的cmp函数、lambda函数或者less< >()、greater< >()作为自定义compare对象参数传给sort()函数,达到自定义比较顺序的结果。代码如下:

  1. 使用自定义cmp函数
bool cmp(const int &a, const int &b){
	return a<b;
}
sort(vec.begin(), vec.end(), cmp);
  1. 使用lambda函数
sort(vec.begin(), vec.end(), [](int a, int b){return a<b;});
  1. 使用less< >()greater< >()
sort(vec.begin(), vec.end(), less<int>());
2.自定义排序函数的priority_queue

对于priority_queue(优先队列)可以使用仿函数(函数对象类)自定义compare顺序,代码如下:

class Cmp{
public:
	bool operator()(int a, int b){
		return a<b;
	}
}
priority_queue<int, vector<int>, Cmp> pri_que;
3.问题提出

而自定义sort时并不能使用仿函数名Cmp,例如如下代码是错的:

// 这个代码是错的
class Cmp{
public:
	bool operator()(int a, int b){
		return a<b;
	}
}
sort(vec.begin(), vec.end(), Cmp);

这是为什么呢?

3.什么是仿函数、函数对象类和函数对象

我在查资料时发现网上对仿函数的定义有冲突。

Functors are objects that can be treated as though they are a function
or function pointer.
仿函数(functor)是一个可以被视作函数或者函数指针的对象1

这段说仿函数是一个对象,可以看做是一个函数或者函数指针。

A functor (or function object) is a C++ class that acts like a function. Functors are called using the same old function call syntax. To create a functor, we create a object that overloads the operator().
仿函数(又叫函数对象)是一个可以像函数一样运行的C++类。调用仿函数与调用函数的语法相同。为了产生一个仿函数,我们需要重载类的"()"运算法1

这段又说仿函数是一个重载了"()"运算符的类。到底是类还是对象这里也没有说清楚。
而中文搜索的结果大多是:

仿函数又称为函数对象,是一种能够行使函数功能的类。

我个人倾向于认为仿函数是一个类,也叫函数对象类。而将仿函数实例化得到的对象(函数对象)可以看作一个函数或函数指针。下面给出代码举例:
代码举例:

// 这是一个类,仿函数(函数对象类),重载了"()"运算符
class Cmp{
public:
	bool operator()(int a, int b){
		return a<b;
	}
};
//这是一个对象,是实例化后的仿函数对象(函数对象)
Cmp cmp;
bool a = cmp(1,2);//返回值为true,显式使用Cmp类的对象cmp
bool b = Cmp()(1,2);//返回值为true,隐式地使用Cmp类的对象
// bool c = Cmp(1,2); //这段代码错误,因为Cmp是一个类没有经过实例化成一个对象。
二、原因
1.sort源代码

从sort函数的定义如下2:

template< class RandomIt, class Compare >
constexpr void sort( RandomIt first, RandomIt last, Compare comp );

可以看到sort是一个模板函数,这里需要三个输入参数(完整的sort函数并不必须要有三个输入参数,详情见2)。
第一、二个参数是需要排序的迭代器,第三个参数comp是一个Compare类的对象

2.priority_queue源代码

priority_queue的定义如下3:

template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> class priority_queue;

priori_queue是一个模板类,类型参数表为T、Container和Compare,这三者都是类(Class)。我们关注的Compare类默认为std::less< typename Container::value_type>。

3.总结

从上面我们可以知道。对于模板函数sort,我们需要在sort的参数列表"()"中给出自定义的Compare类的对象实例,而对于模板类priority_queue,我们需要在其类型参数表 "<>"中给出自定义的Compare类
因此使用仿函数作为cmp的合法代码如下:

class Cmp{
public:
	bool operator() (int a, int b){
		return a<b;
	}
};
...
sort(vec.begin(), vec.end(), Cmp());	//这里Cmp()相当于一个类Cmp实例化后的对象
// 或者也可以这样
Cmp cmp;
sort(vec.begin(), vec.end(), cmp);		// 这里的cmp是一个Cmp类型的对象
// priori_queue中类型参数表中使用Cmp类名,而不是Cmp类具体实例化后的对象
priority_queue<int, vector<int>, Cmp> pri_que;	//

这就是sort和priority_queue在使用仿函数做自定义比较参数时的不同。
至于为什么一个需要 使用实例化后的对象,一个需要使用类名。相信读者也可以看出,因为本质上sort是一个函数,函数参数列表中需要传入实例化后的具体对象,而priority_queue是一个模板类,模板的类型参数表中<>需要传入具体的类,而不是对象。

四、其他

还有一个问题是,priority_queue的类型参数列表中需要传入类名,而lambda函数是一个匿名的类型,所以不能直接使用lambda函数声明priority_queue,需要做些改变,具体的用法可以参考这篇博客,本文中部分内容也参考了该文章。


  1. www.geeksforgeeks.org/functors-in-cpp ↩︎ ↩︎

  2. https://en.cppreference.com/w/cpp/algorithm/sort ↩︎ ↩︎

  3. https://en.cppreference.com/w/cpp/container/priority_queue ↩︎

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值