C++需要澄清代码
我试图理解下面的代码所说的内容:
structcompare_pq;
struct compare_pq {
bool operator() (Events *& a, Events *& b);
};
std::priority_queue<Events *, std::vector<Events *>, compare_pq> eventList;
我查看了priority_queue是什么以及它是如何声明的,但无法停止理解compare_pq
在priority_queue eventList
中做什么。另外,operator()
是做什么的,因为我之前从未见过 *&
和空运算符重载 operator()
!
任何帮助将不胜感激。谢谢
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
operator()
是函数调用运算符。它允许您像使用函数一样使用类类型的对象,例如,重载
operator()
的类类型的对象通常称为函数对象或函子。std::priority_queue
的第三个模板参数用于比较函数。默认情况下,优先级队列使用std::less
对其元素进行排序,这会将operator<
应用于两个元素。您可以使用任何接受两个元素并返回一个布尔值的函数(或函数对象),指示第一个元素是否小于第二个元素。在这种情况下,“较小”是一个相对术语:优先级队列的top()
是队列中当前“最大”的元素。在这种情况下,您需要使用自定义比较函数,因为优先级队列存储指针,因此默认情况下它会按指针值对元素进行排序。自定义比较器(可能)取消引用指针并对指向的对象执行一些比较。
Events*&
只是对Events
对象的指针的引用。它确实不需要通过引用传递。由于它只是一个指针,因此可以按值传递(例如,Events*
)。如果您出于某种原因选择使用引用,那么它应该是 const 引用。operator()
is the function-call operator. It allows you to use an object of the class type as if it were a function, e.g.,Objects of class types that overload
operator()
are frequently called function objects or functors.The third template parameter of
std::priority_queue
is for the comparison function. By default, the priority queue sorts its elements usingstd::less
, which appliesoperator<
to two elements. You can use any function (or function object) that takes two elements and returns a boolean indicating whether the first is smaller than the second. "Smaller" in this case is a relative term: thetop()
of the priority queue is the "largest" element currently in the queue.In this case, you need to use a custom comparison function because the priority queue is storing pointers, so by default it would sort the elements by pointer value. The custom comparator (probably) dereferences the pointers and performs some comparison on the pointed-to objects.
Events*&
is just a reference to a pointer to anEvents
object. It really doesn't need to be passed by reference. Since it's just a pointer, it can be passed by value (e.g.,Events*
). If you do choose for some reason to use a reference it should be a const reference.*&是对指针的引用。它的工作原理与任何其他类型的参考一样。在不太复杂的 C++ 代码中,您可能会看到使用双指针 (**)。
Compare_pq 是一个用于比较事件指针的函子。在这种情况下,每当需要比较时,priority_queue 可能会实例化一个compare_pq。
运算符()不为空。您正在查看一份声明。如果要实例化它,则必须在其他地方定义它。
*& is a reference to a pointer. It works like any other kind of reference. In less sophisticated C++ code you might see a double pointer (**) used.
compare_pq is a functor used to compare Event pointers. In this case, priority_queue would likely be instantiating a compare_pq whenever a comparison is needed.
operator() is not empty. You're looking at a declaration. It must be defined somewhere else if it is to be instantiated.
我将尝试回答为什么使用函子的问题。当然,这只是一个猜测,因为我不是代码的作者,但我至少看到过几次关于它的讨论,而且共识似乎是,函子启用或至少使内联比较代码变得更容易。
函子是结构(或类),通常比常规函数更灵活,因为它们可以有一些成员,存储一些状态,可供operator()使用。在这种情况下,没有使用此优势,因此仿函数最有可能用于启用(或帮助)内联,或者只是因为作者习惯了这种常见模式。
为什么它有助于内联?让我们看一个简单的例子。让我们以 std::sort 为例,
假设您想要对 std::vector 进行排序,并且想要提供自定义比较器。
现在您可以通过以下方式使用
sort
模板以下是编译器从模板创建的函数
由于排序模板中的 Compare 参数是类型,而函子是类型,因此编译器会创建不同的函数作为模板参数提供的每个函子的函数。
sort::iterator, MyStrucComp1>
和sort::iterator, MyStrucComp2>
是两个不同的函数。因此,当创建sort::iterator, MyStrucComp1>
时,就可以准确地知道比较代码是什么,并且可以简单地内联比较器。然而,函数
myFunctComp
1 和myFunctComp2
的类型完全相同:bool (*) (int lhs, int rhs)
并且编译器创建一个函数sort::iterator, bool (*) (int lhs, int rhs)>
适用于bool (*) (int lhs, int rhs)
类型的所有比较函数。我看到了意见,在这种情况下无论如何内联都是可能的,但我不知道如何做。可以使用指向函数的指针作为模板参数创建模板,因为它是编译时常量,但它很丑陋,并且无法从函数参数中推导出常量。例如,如果
sort
定义为:您必须像这样调用它
您将为每个比较函数获得不同的排序,但函子要方便得多。
I'll try to answer the question why a functor is used. It's just a guess of course, as I'm not the author of the code, but I saw discussions about it at least a few times and the consensus seems to be, that functors enable or at least make it easier to inline the comparison code.
Functors are structs (or classes) and in general are more flexible than regular functions because they can have some members, that store some state, which can be used by operator(). In this case this advantage isn't used, so the functor was most probably used to enable (or help) in inlining or just because the author was used to this common pattern.
Why would it help in inlining? Let's look at a simple example. Lets take
std::sort
Imagine You want to sort
std::vector<int>
and You want to provide Your custom comparators.Now You can use the
sort
temeplate in the following waysHere are the function the compiler creates form the template
Since the Compare parameter in the sort template is a type, and functors are types, the compiler creates a different function for every functor supplied as a template argument.
sort<vector<int>::iterator, MyStrucComp1>
andsort<vector<int>::iterator, MyStrucComp2>
are two different functions. So whensort<vector<int>::iterator, MyStrucComp1>
is created, it is known exactly what the comparing code is and the comparator can be simply inlined.Functions
myFunctComp
1 andmyFunctComp2
however are of exactly the same type:bool (*) (int lhs, int rhs)
and the compiler creates one functionsort<vector<int>::iterator, bool (*) (int lhs, int rhs)>
for all comparing functions of typebool (*) (int lhs, int rhs)
. I saw opinions, that inlining is possible anyway in this situation, but I have no idea how.It is possible to create templates with a pointer to function as a template parameter as it's a compile time constant, but it's ugly and constants can't be deduced from the function arguments. For example if
sort
was defined as:You would have to call it like this
You would get a different sort for every comparing function, but functors are much more convenient.