我有一段令我困惑的代码:
sort(data, data+count, greater<int>() );
它是C标准库中的排序函数。我无法弄清楚第三个论点的含义。我已经读过它被称为二元谓词。这意味着什么?我如何制作自己的谓词呢?
答案 0 :(得分:25)
第三个参数称为predicate。您可以将谓词视为一个函数,该函数接受多个参数并返回true
或false
。
因此,例如,这是一个谓词,告诉您整数是否为奇数:
bool isOdd(int n) {
return n & 1;
}
上面的函数只接受一个参数,因此您可以将其称为 unary 谓词。如果它改为使用两个参数,则称其为 binary 谓词。这是一个二元谓词,告诉你它的第一个参数是否大于第二个:
bool isFirstGreater(int x, int y) {
return x > y;
}
谓词通常由非常通用的函数使用,以允许函数的调用者通过编写自己的代码来指定函数的行为(当以这种方式使用时,谓词是 {的特殊形式。 {3}} 的)。例如,在必须对整数列表进行排序时,请考虑sort
函数。如果我们想要在所有偶数之前对所有奇数进行排序怎么办?每次我们想要更改排序顺序时,我们不希望被强制编写新的排序函数,因为排序的机制(算法)显然与细节无关(我们希望它以什么顺序)排序)。
因此,让我们给sort
一个我们自己的谓词,使其反向排序:
// As per the documentation of sort, this needs to return true
// if x "goes before" y. So it ends up sorting in reverse.
bool isLarger(int x, int y) {
return x > y;
}
现在这将按相反的顺序排序:
sort(data, data+count, isLarger);
这种方法的工作方式是sort
在内部比较整数对,以决定哪一个应该先于另一个整数。对于这样一对x
和y
,它通过调用isLarger(x, y)
来完成此操作。
所以在这一点上你知道谓词是什么,你可以在哪里使用它,以及如何创建自己的谓词。但greater<int>
是什么意思?
callback是一个二元谓词,它告诉它的第一个参数是否大于第二个参数。它也是模板struct
,这意味着它根据参数的类型有许多不同的形式。需要指定此类型,因此greater<int>
是类型int
的模板特化(如果您认为有必要,请阅读有关C ++模板的更多信息)。
因此,如果greater<T>
是struct
,它又如何成为谓词?我们不是说谓词是函数吗?
嗯,greater<T>
是一个函数,因为它是 callable :它定义了运算符bool operator()(const T& x, const T& y) const;
,这使得写法合法:
std::greater<int> predicate;
bool isGreater = predicate(1, 2); // isGreater == false
可调用的类类型(或struct
s,在C ++中几乎相同)的对象称为 greater<T>
或仿函数
答案 1 :(得分:6)
有一个名为greater
的类模板需要一个类型参数。所以你提供int
作为一个。它变为greater<int>
并且您创建此类的实例并将其作为第三个参数传递给函数。
这样的对象在C ++中称为function object or simply functor,因为类会重载()
运算符。它是一个可调用的实体。它是这样的:
template<typename T>
struct greater
{
bool operator()(const T &a, const T &b)
{
//compare a and b and return either true or false.
return a > b;
}
};
如果你创建一个greater<int>
的实例,比如说对象是g
,那么你可以编写g(100,200)
来计算一个布尔值,作为表达式{{1} }调用g(100,200)
,将operator()
作为第一个参数传递,将100
作为第二个参数传递,200
比较它们并返回operator()
或true
。
false
输出:
std::cout << g(100,200) << std::endl;
std::cout << g(200,100) << std::endl;
答案 2 :(得分:2)
二元谓词是接收两个对象(因此是二进制)并返回bool
(因此predicate)的任何函数/对象;我们的想法是评估两个对象是否满足某些特定条件 - 在本例中,如果一个对象大于另一个对象。
您可以通过定义具有正确签名的函数来创建谓词
bool IsIntGreater(int First, int Second)
{
return First>Second;
}
并传递函数的名称作为参数(这将导致传递函数指针),或创建函数对象(仿函数),即重载函数调用运算符的对象因此可以用作功能; std::greater<T>
类型是模板函子,在您的代码段中创建了std::greater<int>
类型的临时对象并将其传递给std::sort
算法。
Functors比函数有几个优点,特别是当它们必须作为参数传递时,请查看here以获取有关此函数的更多信息。
答案 3 :(得分:1)