需要C ++代码澄清

时间:2010-05-05 00:28:40

标签: c++ operator-overloading

我正在尝试理解下面的代码:

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()

任何帮助将不胜感激。谢谢

3 个答案:

答案 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());

对于每个比较函数,您会得到不同的排序,但是仿函数更方便。