Я пытаюсь реализовать различные структуры данных и алгоритмы для обучения.
На данный момент я пытаюсь реализовать шаблон класса Graph, но у меня возникают проблемы с попыткой использовать STL unordered_map
(и, consequently priority_queue
в будущем).
В основном, что происходит на данный момент, по некоторым причинам типы шаблонов не совпадают при попытке инициализировать карту вершин внутри графика. Из того, что я понимаю, поскольку я только планирую использовать ключевые типы из родных типов C++, пока мой тип значения является указателем, мне не нужно делать какую-либо дополнительную работу отдельно от конструктора копирования для моего пользовательского класса вершин, По умолчанию для сравнения/хэширования должно быть достаточно. Но это не так, и ошибка, которую я получаю, является непонятной.
Ошибка:
Error 1 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::unordered_map<T,graph<T>::vertex *,std::hash<int>,std::equal_to<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' (or there is no acceptable conversion)
Код:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <unordered_map>
#include <numeric>
#include <functional>
using namespace std;
class vertex;
template <class T>
class graph {
public:
graph() { verts = unordered_map<T, vertex*>(); }
~graph() {
for each(auto v in verts)
delete(v);
delete(verts);
}
private:
unordered_map<T, vertex*> verts;
// --- Inner Classes ---
struct path {
vertex *dest;
double cost;
path(vertex *d = nullptr, double c = 0.0) : dest(d) : cost(c) {}
inline int compare(const path& p) {
auto other = p.cost;
return cost < other ? -1 :
cost > other ? 1 : 0;
}
};
struct edge {
vertex *dest;
double cost;
edge(vertex *d = nullptr, double c = 0.0) : dest(d) : cost(c) {}
};
class vertex {
public:
// Vertex relationships
T name;
vector<edge>* adj;
// Path Finding Information
double distance;
vertex *prev;
int scratch;
void reset_path_finding() {
distance = double.infinity();
prev = nullptr;
scratch = 0;
}
vertex(T name = default(T)) : name(name) : adj(new vector<edge>) :
distance(double.infinity()) : prev(nullptr) : scratch(0) {}
vertex(const vertex& v) {
name = v.name;
adj = v.adj;
distance = v.distance;
prev = v.prev;
scratch = v.scratch;
}
~vertex() { delete(adj); }
private:
};
};
int main()
{
graph<int> myGraph = graph<int>();
cout << "Press any key to continue..." << endl;
int x;
cin >> x;
return 0;
}
Первая проблема заключается в том, что перед объявлением его вы используете graph::vertex
вложенного класса graph::vertex
. Дальнейшая путаница вызвана тем, что вы объявили class vertex
вне graph
, поэтому компилятор изначально думает, что вы имеете в виду этот класс. Вы можете объявить vertex
около начала graph
:
template <class T>
class graph {
class vertex;
private:
// and so on
};
Существует еще несколько синтаксических ошибок, которые должны быть очевидны, если вы посмотрите на строки, на которые ссылаются сообщения об ошибках. Синтаксис для цикла, основанного на диапазоне, равен
for (auto v : verts) // not for each(auto v in verts)
Это дает вам пары ключ-значение, поэтому для удаления vertex
вам нужно
delete v.second;
Еще лучше измените verts
в unordered_map<T, vertex>
, содержащий объекты, а не указатели, и автоматически будет управлять всей своей памятью - вам вообще не понадобится деструктор.
Синтаксис для инициализируемого значения временного
T() // not default(T)
Классы в списке инициализаторов конструктора разделяются запятыми, а не двоеточиями:
path(vertex *d = nullptr, double c = 0.0) : dest(d) , cost(c) {}
^ not :
double
с бесконечным значением
std::numeric_limits<double>::infinity() // not double.infinity()
для которых вам необходимо включить <limits>
.
verts
не нужно удалять в деструкторе, так как вы его не new
. Также не нужно назначать из созданного по умолчанию временного элемента в конструкторе, поскольку он просто был сконфигурирован по умолчанию.
Есть несколько мест, где вы делаете жизнь трудной для себя, используя излишнее использование указателей и new
. Старайтесь избегать new
кроме случаев, когда вам это действительно нужно; и узнайте об RAII, особенно о использовании интеллектуальных указателей и контейнеров, когда вы это сделаете.
myGraph
вmain
функции илиverts
в классеgraph
, вам не нужно инициализировать, как вы это делаете. Просто объявив это будет достаточно.