Требуется разъяснение кода C ++ - PullRequest
1 голос
/ 05 мая 2010

Я пытаюсь понять, что говорит код ниже:

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 ]

6 голосов
/ 05 мая 2010

operator() - оператор вызова функции. Он позволяет вам использовать объект типа класса, как если бы он был функцией, например,

compare_pq my_comparator;
bool result = my_comparator(a, b);

Объекты типов классов, которые перегружают operator(), часто называют функциональными объектами или функторами.

Третий параметр шаблона std::priority_queue предназначен для функции сравнения. По умолчанию очередь с приоритетами сортирует свои элементы, используя std::less, который применяет operator< к двум элементам. Вы можете использовать любую функцию (или функциональный объект), которая принимает два элемента и возвращает логическое значение, указывающее, меньше ли первое, чем второе. «Меньше» в данном случае является относительным термином: top() очереди с приоритетами является «самым большим» элементом в очереди в настоящее время.

В этом случае вам нужно использовать пользовательскую функцию сравнения, поскольку в очереди приоритетов хранятся указатели, поэтому по умолчанию она сортирует элементы по значению указателя. Пользовательский компаратор (вероятно) разыменовывает указатели и выполняет некоторое сравнение с указанными объектами.

Events*& - это просто ссылка на указатель на объект Events. Это действительно не должно быть передано по ссылке. Поскольку это просто указатель, его можно передавать по значению (например, Events*). Если вы по какой-то причине решили использовать ссылку, это должна быть постоянная ссылка.

2 голосов
/ 05 мая 2010

* & является ссылкой на указатель. Это работает как любой другой вид ссылки. В менее сложном коде C ++ вы можете увидеть использование двойного указателя (**).

compare_pq - это функтор, используемый для сравнения указателей событий. В этом случае priority_queue, вероятно, будет создавать экземпляр Compare_pq всякий раз, когда необходимо сравнение.

Event * a = new Event();
Event * b = a;
compare_pq foo;
bool result = foo(a, b);

operator () не пустой. Вы смотрите на декларацию. Он должен быть определен где-то еще, если он будет создан.

1 голос
/ 05 мая 2010

Я постараюсь ответить на вопрос, почему используется функтор. Конечно, это всего лишь предположение, поскольку я не являюсь автором кода, но я видел дискуссии по этому поводу, по крайней мере, несколько раз, и, похоже, все согласны с тем, что функторы позволяют или, по крайней мере, облегчают вставку кода сравнения ,

Функторы являются структурами (или классами) и в целом более гибкие, чем обычные функции, потому что они могут иметь несколько членов, которые хранят некоторое состояние, которое может использоваться оператором (). В этом случае это преимущество не используется, поэтому, скорее всего, функтор использовался для включения (или помощи) во встраивании или просто потому, что автор привык к этому общему шаблону.

Почему это поможет при встраивании? Давайте посмотрим на простой пример. Давайте возьмем 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 следующими способами

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

Поскольку параметр Compare в шаблоне sort является типом, а функторы - типами, компилятор создает разные функции для каждого функтора, представленного в качестве аргумента шаблона. 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());

Вы могли бы получить различный вид для каждой функции сравнения, но функторы намного удобнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...