Это может показаться вам абсолютно логичным, но компилятор понятия не имеет, что заказывает ваше концептуальное определение «приоритет» означает вашу вещь под названием Coord
. Ваши объекты хранятся в вашем взгляде очереди, как это:
std::pair<int, Coord>
и понимание того, как std::priority_queue
сравнивает элементы гарантировано.
Адаптер std::priority_queue
по умолчанию использует std::less
для сравнения товара. Как вы теперь обнаружили, этот компаратор делает немного больше, чем создание простой конструкции для сравнения объектов для заказа, и если класс объекта (или его базы) предоставляет это, отлично; если нет, вам нужно это сделать. как выясняется, std::pair
does provide an operator <
, который в основном устанавливает строгий слабый порядок по first
и second
. Для двух объектов пары она по существу делает это:
return lhs.first < rhs.first || (!(rhs.first < lhs.first) && lhs.second < rhs.second);
Почему что важно? Обратите внимание, что использование second
в последнем выражении.Это важно, потому что second
в приведенном выше номере ваш тип Coord
, поэтому operator <
применяется к Coord
, и так как такого оператора нет, компилятор = не-доволен.
В качестве побочного сведению, вы заметили это Works из коробки для std::pair<int, std::pair<int,int>>
, потому что, как уже упоминалось ранее, std::pair
имеет оператор < overload, and in that case two different instantiations of
оператор < `проявлены.
Чтобы решить эту проблему, вы должны предоставить такой номер operator
для вашего типа. Существует по существу только два способа сделать это: функция-член или свободная функция, каждая из которых определяет перегрузку для Coord
. Обычно реализуемый как функция-член, но также возможный как бесплатная функция, это по существу обеспечивает оператор std::less
. Это наиболее распространенный механизм для обеспечения порядка (и имхо самый простой для понимания):
// member function
struct Coord
{
int x, y;
bool operator <(const Coord& rhs)
{
return x < rhs.x || (!(rhs.x < x) && y < rhs.y)
}
};
или
// free function
bool operator <(const Coord& lhs, const Coord& rhs)
{
return lhs.x < rhs.x || (!(rhs.x < lhs.x) && lhs.y < rhs.y)
}
Общие Компаратор Руководство
Beyond делает std::less<>
счастливым для данного типа путем перегрузки operator <
, множества контейнеров, адаптеров и алгоритмов a llow, чтобы предоставить свой собственный тип компаратора. Например:
std::map
std::set
std::sort
std::priority_queue
- многие другие ...
Для этого существует несколько возможных способов сделать это. Примеры включают в себя:
- Обеспечить
operator <
для экземпляров вашего Type
типа (легкий, пример, показанный перед). Это позволяет продолжать работу по умолчанию std::less
, чтобы выполнить свою работу по стрельбе operator <
, предоставленной вами.
- Представьте компаратор для контейнера/алгоритма, который выполняет сравнение для вас (также легко). В сущности, вы пишете замену для
std::less
, что вы укажите для контейнера, адаптатора или алгоритма при их объявлении или вызове.
- Предоставьте шаблон специализации
std::less<Coord>
(умеренно легкий, но редко сделанный и менее интуитивный для начинающих). Это заменяетstd::less
с вашей специализацией везде, где бы это обычно не использовать.
Ниже приведены примеры двух последних.Мы будем считать, что мы просто используем свой Coord
, а не ваши std::pair<int, Coord>
, пояснялось ранее
Обеспечение пользовательского компаратор
Вы не должны использовать std::less
для заказа. Вы также можете предоставить свой собственный функтор, который выполняет ту же работу. Параметр третьего шаблона std::priority_queue
является то, что вы используете, чтобы обеспечить это:
struct CoordLess
{
bool operator()(Coord const& lhs, Coord const& rhs) const
{
return lhs.x < rhs.x || (!(rhs.x < lhs.x) && lhs.y < rhs.y)
}
};
std::priority_queue<Coord, std::vector<Coord>, CoordLess> myqueue;
Это удобно, когда вам нужно реализовать различные упорядоченности на одном классе объектов для различных контейнеров. Например, у вас может быть один контейнер, который заказывает мало-по-крупному, другой большой-маленький. Различные компараторы позволяют это сделать. Например, вы можете создать std::set
из Coord
объектов с вашего компаратора делая
std::set<Coord, CoordLess> myset;
или сортировать такой вектор vec
из Coord
объектов, делая это:
std::sort(vec.begin(), vec.end(), CoordLess());
Примечание В обоих случаях мы указываем в декларации или вызов пользовательского компаратора.
Обеспечить std::less
специализацию
Это не так легко понять, делается редко, но столь же легко реализовать. Поскольку std::less
является компаратором по умолчанию, если тип является настраиваемым (не тип родного языка или тип библиотеки), вы можете предоставить std::less
специализацию для Coord
. Это означает, что все, которое обычно использует std::less<Coord>
для заказа, получит это неявно, если приведенное ниже определение предоставляется заранее.
namespace std
{
template<>
struct less<Coord>
{
bool operator()(Coord const& lhs, Coord const& rhs) const
{
return lhs.x < rhs.x || (!(rhs.x < lhs.x) && lhs.y < rhs.y)
}
};
}
При том, что при условии (как правило, сразу же после вашего пользовательского типа в том же заголовке), вы можете просто использовать параметры шаблона по умолчанию, тогда как раньше мы должны были указать их. Например теперь мы можем объявить std::set
как это:
std::set<Coord> myset;
или выполнить то вроде этого:
std::sort(vec.begin(), vec.end());
Оба этих умолчанию для использования std::less<Coord>
и, так как мы сами, что специализированные, он использует наш. Это удобный, обволакивающий способ изменения поведения по умолчанию в многих местах, но с большой силой приносит большую ответственность, поэтому будьте осторожны, и никогда не делают это с помощью родных или библиотечных типов.
Надеемся, что вы дадите несколько идей по различным способам решения вашей ошибки.
Это было абсолютно фантастически. Очень исчерпывающий ответ, большое спасибо! –