我正在尝试理解下面的代码:
struct compare_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()
!
任何帮助将不胜感激。谢谢
答案 0 :(得分:6)
operator()
是函数调用运算符。它允许您使用类类型的对象,就好像它是一个函数,例如,
compare_pq my_comparator;
bool result = my_comparator(a, b);
重载operator()
的类类型的对象通常称为函数对象或函子。
std::priority_queue
的第三个模板参数用于比较功能。默认情况下,优先级队列使用std::less
对其元素进行排序,operator<
将top()
应用于两个元素。您可以使用任何带有两个元素的函数(或函数对象)并返回一个布尔值,指示第一个是否小于第二个元素。在这种情况下,“较小”是一个相对术语:优先级队列的Events*&
是当前队列中的“最大”元素。
在这种情况下,您需要使用自定义比较函数,因为优先级队列存储指针,因此默认情况下它会按指针值对元素进行排序。自定义比较器(可能)取消引用指针并对指向对象执行一些比较。
Events
只是对指向Events*
对象的指针的引用。它确实不需要通过引用传递。由于它只是一个指针,因此可以通过值传递(例如,{{1}})。如果您因某种原因选择使用引用,那么它应该是const引用。
答案 1 :(得分:2)
*&安培;是指针的引用。它的工作方式与其他任何参考类似。在不太复杂的C ++代码中,您可能会看到使用了双指针(**)。
compare_pq是一个用于比较事件指针的函子。在这种情况下,每当需要进行比较时,priority_queue可能会实例化compare_pq。
Event * a = new Event();
Event * b = a;
compare_pq foo;
bool result = foo(a, b);
operator()不为空。你正在看一份宣言。如果要实例化它,必须在其他地方定义。
答案 2 :(得分:1)
我会尝试回答为什么使用仿函数的问题。这只是一个猜测当然,因为我不是代码的作者,但我至少看过几次关于它的讨论并且共识似乎是,函子启用或至少使得更容易内联比较代码。
Functors是结构(或类),并且通常比常规函数更灵活,因为它们可以有一些成员,它们存储一些可由operator()使用的状态。在这种情况下,没有使用这个优点,因此函数很可能用于启用(或帮助)内联,或者仅仅因为作者习惯了这种常见模式。
为什么它有助于内联?我们来看一个简单的例子。让我们来std::sort
template <class RandomAccessIterator, class Compare>
void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
想象一下,您想要对std::vector<int>
进行排序,并希望提供自定义比较器。
struct MyStructComp1
{
bool operator()(int lhs, int rhs) const { /*...*/}
};
struct MyStructComp2
{
bool operator()(int lhs, int rhs) const { /*...*/}
};
bool myFunctComp1 (int lhs, int rhs) const { /*...*/}
bool myFunctComp2 (int lhs, int rhs) const { /*...*/}
现在您可以通过以下方式使用sort
temeplate
sort(myvector.begin(), myvector.end(), MyStructComp1()); // 1
sort(myvector.begin(), myvector.end(), MyStructComp2()); // 2
sort(myvector.begin(), myvector.end(), myFunctComp1); // 3
sort(myvector.begin(), myvector.end(), myFunctComp2); // 4
以下是编译器从模板中创建的函数
sort<vector<int>::iterator, MyStrucComp1> // 1
sort<vector<int>::iterator, MyStrucComp2> // 2
sort<vector<int>::iterator, bool (*) (int lhs, int rhs)> // 3, // 4
由于sort模板中的Compare参数是一个类型,而functor是类型,因此编译器会为作为模板参数提供的每个functor创建一个不同的函数。 sort<vector<int>::iterator, MyStrucComp1>
和
sort<vector<int>::iterator, MyStrucComp2>
是两个不同的功能。因此,当创建sort<vector<int>::iterator, MyStrucComp1>
时,确切地知道比较代码是什么,比较器可以简单地内联。
函数myFunctComp
1和myFunctComp2
的类型完全相同:
bool (*) (int lhs, int rhs)
并且编译器为类型sort<vector<int>::iterator, bool (*) (int lhs, int rhs)>
的所有比较函数创建一个函数bool (*) (int lhs, int rhs)
。我看到了意见,无论如何在这种情况下内联是可能的,但我不知道如何。
可以创建带有指针的模板作为模板参数,因为它是一个编译时常量,但它很难看,并且不能从函数参数中推导出常量。例如,如果sort
被定义为:
template <class RandomAccessIterator,
bool (*comparer) (typename RandomAccessIterator::value_type, typename RandomAccessIterator::value_type)>
void sort ( RandomAccessIterator first, RandomAccessIterator last) {/* */}
你必须像这样称呼它
sort<std::vector<int>::iterator, myFunctComp1>(myvector.begin(), myvector.end());
对于每个比较函数,您会得到不同的排序,但是仿函数更方便。