在下面的代码中,为什么三个IntComparator()
,IntComparator2
和IntComparator3
都作为sort()
函数的第三个参数?它们不会具有不同的l值函数类型吗?根据{{3}}说
比较功能的签名应等效于 以下:
bool cmp(const Type1&a,const Type2&b);
哪个更匹配IntComparator2
?
还有哪个更合适?第三种选择似乎更简单,更直观。
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
struct IntComparator
{
bool operator()(const int &a, const int &b) const
{
return a < b;
}
};
bool IntComparator2 (const int &a, const int &b)
{
return a < b;
}
bool IntComparator3 (int a, int b)
{
return a < b;
}
int main()
{
int items[] = { 4, 3, 1, 2 };
std::sort(items, items+4, IntComparator());
for (int n=0; n<4; n++) {
std::cout << items[n] << ", ";
}
std::cout << "\n";
int items2[] = { 4, 3, 1, 2 };
std::sort(items2, items2+4, IntComparator2);
for (int n=0; n<4; n++) {
std::cout << items2[n] << ", ";
}
std::cout << "\n";
int items3[] = { 4, 3, 1, 2 };
std::sort(items3, items3+4, IntComparator3);
for (int n=0; n<4; n++) {
std::cout << items3[n] << ", ";
}
std::cout << "\n";
return 0;
}
答案 0 :(得分:6)
std::sort
接受functor
。这是可以调用的任何对象(带有正确的参数)。该功能通过使用以下模板来实现此目的
template<typename Iter, typename Comp>
void sort(Iter begin, Iter end, Comp compare) { ... }
IntComparator1
,2和3都是该比较器的有效函子,因为它们都可以使用带有2个整数的operator()进行调用。
也像您说的那样,第三个选项通常确实更直观。
答案 1 :(得分:1)
sort()
函数将仅在需要进行比较时调用您提供的比较器函数。比较器获取其参数(值,引用,const ref)的方式与sort()
无关,无论您的比较器如何获取其参数,它都将以相同的方式调用(传递相同类型的两个参数)在内部。
从比较器定义的外部很难察觉,因为我们调用三个函数的方式是完全相同的。
唯一需要的是比较器仅接受两个参数,并且它们必须与要排序的元素类型相同。
但是,通过const ref传递更好,因为您的比较器保证不修改其比较的参数,并且还避免了无用的副本(性能增益)。这就是为什么他们写 应该等效 的原因(与 必须等效 不同)。
答案 2 :(得分:1)
它们是等效的,因为C ++规范说它们都符合二进制谓词的要求。以下摘录似乎很相关。
20.14.1函数对象类型是可以作为函数调用([expr.call],[over.match.call])中的后缀表达式的类型的对象类型。224功能对象类型的对象。 在人们期望将指向函数的指针传递到算法模板的地方,接口被指定为接受函数对象。这不仅使算法模板可以使用指向函数的指针,还可以使它们与任意函数对象一起使用。
25.7.2 比较是一种功能对象类型([function.objects]),它满足名为BinaryPredicate([algorithms.requirements])的模板参数的要求。应用于上下文类型为对象的对象的函数调用操作的返回值在上下文中转换为bool([conv])时,如果调用的第一个参数小于第二个参数,则返回true,否则返回false。假定有排序关系,整个算法都使用Compare comp。
25.2.8在没有其他限制的情况下,只要算法期望函数对象应用到对两个对应的迭代器进行解引用或对迭代器进行解引用的结果时使用BinaryPredicate参数,并且当T是签名的一部分时返回类型T。可测试为真的值。换句话说,如果某个算法将BinaryPredicate binary_pred作为其参数,并将first1和first2作为其迭代器参数,且其值类型分别为T1和T2,则它应在上下文转换为bool([转换])。除非另有说明,否则BinaryPredicate始终将第一个迭代器的value_type作为其第一个参数,也就是说,在那些T值是签名的一部分的情况下,它应该在上下文转换为bool的结构binary_pred(* first1,value)中正确工作。 [转换])。 binary_pred不得通过解引用的迭代器应用任何非常数函数。 给出一个类型(可能为const)T1的glvalue u,它指定与* first1相同的对象;给出一个类型为(可能为const)T2类型的glvalue v,它与* first2指定相同的对象,binary_pred(u,* first2) ,binary_pred(* first1,v)和binary_pred(u,v)均应为有效表达式,该表达式等于binary_pred(* first1,* first2),binary_pred(u,value)应为有效表达式等于binary_pred(* first1,value)的表达式。
关于哪个是更可取的问题,我想说这是基于观点的,除非在您的特定情况下,剖析显示更好。