C ++: структура против функции для упорядочивания элементов - PullRequest
6 голосов
/ 29 апреля 2019

У меня есть struct с двумя полями:

struct road {
    int from, len ;
};

По какой-то причине мне нужно иметь возможность заказать мои road s:

  • по возрастанию from в массиве

  • по возрастанию len в очереди с приоритетами

Таким образом, я включил:

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>

Я сталкивался с сайтами, предлагающими перегрузить operator<, но из-за двух возможных порядков, которые просто кажутся неправильными, и это может решить только один из двух.

Путем возиться сучебники, я получил это на работу:

bool cmpFrom (const road & a, const road & b) {
    return (a.from < b.from) ;
}

struct cmpLen {
    bool operator () (const road & a, const road & b){
        return (a.len < b.len) ;
    }
};

Для использования с:

std::sort(trips, trips + nbRoads, &cmpFrom) ;
std::priority_queue<road, std::vector<road>, cmpLen> pickRoad ;

Где trips, конечно, road [].

Этопрекрасно компилируется (не пробовал запускать его, но это должно быть хорошо), но кажется странным определять два очень похожих компаратора двумя совершенно разными способами, так что, разве нет способа определить оба метода сравнения одинаково?

Изменение определения cmpFrom на

struct cmpFrom {
    bool operator () (const road & a, const road & b){
        return (a.from < b.from) ;
    }
};

Дает

chantier.cpp: In function ‘int main()’:
chantier.cpp:38:48: error: expected primary-expression before ‘)’ token
     std::sort(trips, trips + nbRoads, &cmpFrom) ;

Что, как я предполагаю, означает "Вы дали мтипа, когда я ожидал ссылку ".

Во время записи

bool cmpLen (const road & a, const road & b) {
    return (a.len <= b.len) ;
}

Дает

chantier.cpp: In function ‘int main()’:
chantier.cpp:52:56: error: type/value mismatch at argument 3 in template parameter list for ‘template<class _Tp, class _Sequence, class _Compare> class std::priority_queue’
     std::priority_queue<road, std::vector<road>, cmpLen> pickRoad ;
                                                        ^
chantier.cpp:52:56: note:   expected a type, got ‘cmpLen’
chantier.cpp:56:30: error: request for member ‘top’ in ‘pickRoad’, which is of non-class type ‘int’
...

Есть ли способ заставить один из этих методов сравнения работать дляоба контейнера?Или, возможно, существует третий способ сделать это, который мог бы работать с обоими?

Что если бы мне нужно было использовать один и тот же порядок для обоих контейнеров?Потребовалось бы дважды определить один и тот же метод сравнения, но с одним внутри struct?

Ответы [ 3 ]

5 голосов
/ 29 апреля 2019

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

На самом деле вы были почти там с struct cmpFrom. Однако вы правильно заметили, что std::sort ожидает компаратор объект (например, функцию), а не тип. Конечно, выполнение &cmpFrom, где cmpFrom является типом, недопустимо в C ++. Вместо этого вам нужно создать объект этого типа; благодаря определенному operator() объект будет вызываться и делать то, что вы хотите. Так что просто позвоните std::sort так:

std::sort(trips, trips + nbRoads, cmpFrom{});
5 голосов
/ 29 апреля 2019

У вас почти есть это. В std::sort вам нужен объект, который вы можете вызвать operator(). Использование

bool cmpFrom (const road & a, const road & b) {
    return (a.from < b.from) ;
}
std::sort(trips, trips + nbRoads, &cmpFrom);

работает, потому что указатель на функцию можно использовать как функцию. При изменении cmpFrom на

struct cmpFrom {
    bool operator () (const road & a, const road & b){
        return (a.from < b.from) ;
    }
};

вы больше не можете использовать std::sort(trips, trips + nbRoads, &cmpFrom);, потому что вы не можете применить & к имени типа. Вместо этого вам нужно получить объект cmpFrom, и вы сделаете это как

std::sort(trips, trips + nbRoads, cmpFrom{});

теперь и priority_queue, и sort могут использовать cmpFrom.

3 голосов
/ 29 апреля 2019

Функция std::sort и шаблон класса std::priority_queue хотят две разные вещи: sort хочет вызываемый объект , в то время как шаблон priority_queue хочет тип, который позволяет создавать объекты.

Из-за этого sort всеяднее, чем priority_queue - вы можете использовать его с функциями или функторами.Единственное, что вам нужно, это предоставить ему реальный объект (в то время как в настоящее время в вашем коде вы пытаетесь взять адрес типа, который не имеет смысла).

Чтобы исправить это в вашем примере, просто изменитекод для

std::sort(trips, trips + nbRoads, cmpFrom{});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...