2016-12-06 17 views
1

Итак, я пытаюсь создать std::priority_queue, который принимает в качестве параметров пару. Пара имеет параметры int и Coord. Coord - это структура, просто содержащая два ints (x и y) для координат для массива.Почему компиляция стандартной очереди приоритетов для моего класса объектов не выполняется?

Что я пытаюсь сделать с помощью всей моей программы, это реализовать алгоритм Дийкстры на сетке массива (вместо использования графика), который уже дает мне головную боль, потому что я не уверен, что делаю это правильный путь. По крайней мере, я пытаюсь учиться. Но в любом случае эта проблема у меня в настоящее время является то, что когда я компилирую, я получаю ошибку

«C2678 двоичный„<“ни один оператор не найден, который принимает левого операнда типа„Const коорд“(или нет приемлемой конверсии)»

Это как часть моего кода выглядит следующим образом:

struct Coord 
{ 
    int x, y; 
}; 

это основная Coord структура. Тогда есть функция, где я создаю очередь:

void dijkstraFirstPhase(Coord start, Coord end, int(&aGrid)[HEIGHT][WIDTH], unordered_map<pair<int, int>, bool, pair_hash>& theMap) 
{ 
    //priority_queue< pair<int, pair<int, int>> > pq; 
    priority_queue<pair<int, Coord>> pq; //this is the line where the error comes from 

    //initializing the starting point 
    int distanceFromStart = 0; 
    aGrid[start.x][start.y] = distanceFromStart; 
    pq.push({ distanceFromStart, start }); 

    while (!pq.empty()) 
    { 
     Coord u = pq.top().second; 
     theMap[make_pair(u.x, u.y)] = true; 
     pq.pop(); 

     writeDistances(u.x, u.y, aGrid, theMap, pq); 
     displayGrid(aGrid); 

     if (theMap[make_pair(end.x, end.y)] = true) 
     { 
      cout << "The end has been found" << endl; 
      cout << "Distance written into its cell: " << aGrid[end.x][end.y] << endl; 
      break; 
     } 
    } 
} 

Я хотел бы знать, как избавиться от этой ошибки, я не очень хорошо знаком с очередями или парами, но я думал, что я понимал их достаточно что мне нужно было сделать. Что он пытается сравнить с этим оператором? Мне не нужно, чтобы int был меньше, чем Coord в аргументах пары.

Заранее благодарим за помощь. Любые предложения приветствуются, но не сложны, поскольку я все еще новичок с C++ и могу не понимать их.

ответ

2

Это может показаться вам абсолютно логичным, но компилятор понятия не имеет, что заказывает ваше концептуальное определение «приоритет» означает вашу вещь под названием Coord. Ваши объекты хранятся в вашем взгляде очереди, как это:

std::pair<int, Coord> 

и понимание того, как std::priority_queue сравнивает элементы гарантировано.

Адаптер std::priority_queue по умолчанию использует std::less для сравнения товара. Как вы теперь обнаружили, этот компаратор делает немного больше, чем создание простой конструкции для сравнения объектов для заказа, и если класс объекта (или его базы) предоставляет это, отлично; если нет, вам нужно это сделать. как выясняется, std::pairdoes 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> и, так как мы сами, что специализированные, он использует наш. Это удобный, обволакивающий способ изменения поведения по умолчанию в многих местах, но с большой силой приносит большую ответственность, поэтому будьте осторожны, и никогда не делают это с помощью родных или библиотечных типов.

Надеемся, что вы дадите несколько идей по различным способам решения вашей ошибки.

+0

Это было абсолютно фантастически. Очень исчерпывающий ответ, большое спасибо! –

0

Вам необходимо определить операцию сравнения для вашего класса Coord. Добавьте bool operator<(const Coord &rhs) const; к вашему классу, который определит, какой из двух Coords (* this или rhs) на первом месте.

+0

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