Предположим, у меня есть простой класс, подобный этому:
class Test {
public:
Test(int reference) { m_reference = reference; }
void feed(int x) { m_data.push_back(x); }
int get() { return m_data.front(); }
private:
int m_reference;
std::vector<int> m_data;
};
Вместо std::vector
, Я хотел бы кормить ценности в std::priority_queue
. Вместо возврата .front()
значение, я хотел бы .get()
.top()
значение priority_queue
основанный на пользовательской функции сравнения. Допустим, это пользовательское сравнение вычисляется как абсолютная разница между значением и экземпляром reference
,
я имею без понятия как объявить std::priority_queue
в моем классе атрибутов.
Я пытался:
bool compare(int a, int b) {
return std::abs(a - m_reference) < std::abs(b - m_reference);
}
А потом:
std::priority_queue<int, std::vector<int>, decltype(&Test::compare)> m_priority;
Я тоже пробовал с std::function
как это, но это вызывает несколько ошибок:
std::function<bool(int a, int b)>> pq([this](int a, int b){
return std::abs(a - m_reference) < std::abs(b - m_reference);
});
Но это не сработает (см. Repl.it).
Любая идея, как решить эту проблему, пожалуйста?
Мне удалось заставить его работать с помощью:
std::function<bool(int,int)> comp = [this](int a, int b) { return std::abs(a - m_reference) < std::abs(b - m_reference); };
с
Test(int reference) : m_priority(comp) { m_reference = reference; }
а также
std::priority_queue<int, std::vector<int>, decltype(comp)> m_priority;
Вам также нужно #include <functional>
Если я правильно понимаю ваш вопрос, это то, что вы хотели?
Вы также можете сделать свой компаратор struct
или что-то и использовать его вместо std::function
если вы не хотите никаких недостатков производительности.
Обновить:
Версия со структурой будет выглядеть так (вы можете передать this
указатель вместо ссылки на int
или как вы предпочитаете)
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
class Test {
public:
Test(int reference) : m_priority(comp(m_reference)) { m_reference = reference; }
void feed(int x) { m_data.push_back(x); }
int get() { return m_priority.top(); }
struct comp {
int& reference;
comp(int& ref) : reference(ref) {}
bool operator()(int a, int b) { return std::abs(a - reference) < std::abs(b - reference); };
};
private:
int m_reference;
std::vector<int> m_data;
std::priority_queue<int, std::vector<int>, comp> m_priority;
};
Если вы хорошо используете std::function
(это может иметь небольшие накладные расходы), это сработало бы, но вы попытались передать лямбду в объявление типа:
std::priority_queue<
int,
std::vector<int>,
std::function<bool(int,int)> comp = [this](int a, int b) { return std::abs(a - m_reference) < std::abs(b - m_reference); }> m_priority;
это не будет работать. Вам нужно использовать std::function
как тип:
std::priority_queue<
int,
std::vector<int>,
std::function<bool(int,int)>> m_priority;
а затем отправить лямбду в m_priority
ctor как параметр:
Test(int reference) :
m_reference( reference ),
m_priority( [ref=reference]( int a, int b ) {
return std::abs( a - ref ) < std::abs( b - ref );
} )
{
}
тогда это будет работать. Живой пример
Если вы когда-нибудь собираетесь изменить m_reference
значение, вам нужно будет пересортировать std::priority_queue
, Ниже приведен (вероятно) неуклюжий способ сделать это, который будет очень дорогостоящим, если делать его часто и / или очередь большая, но он выполняет свою работу. Код предназначен для дополнения к ответу @Slavas.
public:
void set_reference(int x) {
m_reference = x;
sort();
}
private:
void sort() {
std::priority_queue<int, std::vector<int>, std::function<bool(int,int)>> tmp(
[this](int a, int b) { return std::abs(a - m_reference) < std::abs(b - m_reference); }
);
while(m_priority.size()) {
tmp.emplace(std::move(m_priority.top()));
m_priority.pop();
}
std::swap(tmp, m_priority);
}