8

I am trying to make a generic graph structure, but I am running into this circular dependency between vertices and edges. I define my Vertex and Edge classes like so:

template<typename EdgeType>
struct Vertex {
    std::vector<EdgeType> successors;
};

template<typename EdgeCostType, typename VertexWrapper>
struct Edge {
    EdgeCostType cost;
    VertexWrapper source;
    VertexWrapper dest;
};

I would like to instantiate it with something like Vertex<Edge<int, std::shared_ptr<decltype(v)>>> v;, but I obviously cannot. What can I do to resolve this circular dependency?

Edit:

I think what this problem boils down to is using the current template as a template parameter to one of the template parameters of the current template, e.g. how to do something like this:

template<typename VertexWrapper>
struct Vertex {
    std::vector<pair<int, VertexWrapper<Vertex>>> successors;
};
Simon Berens
  • 554
  • 4
  • 11
  • 2
    `template class VertexWrapper`? Also, why do you have both C++11 and C++17 tags? Which standard are you targeting? – HolyBlackCat Dec 31 '19 at 23:46
  • @HolyBlackCat Afaik both apply, should I only use the most recent one? Also I'm not sure what you mean by `template typename VertexWrapper` – Simon Berens Dec 31 '19 at 23:48
  • Is the `VertexWrapper` type argument always supposed to be of the form `std::shared_ptr` or `some_template_here`? – walnut Dec 31 '19 at 23:52
  • @walnut it should be something like shared_ptr/unique_ptr/something with operator-> – Simon Berens Dec 31 '19 at 23:53
  • If I'm reading this question right, you might want to look into "template template" parameters https://stackoverflow.com/questions/213761/what-are-some-uses-of-template-template-parameters – Joe Jan 13 '20 at 18:03

3 Answers3

10

With template template parameter, you can do something like:

template<typename EdgeType>
struct Vertex {
    std::vector<EdgeType> successors;
};

template<typename EdgeCostType, template <typename> class VertexWrapper>
struct Edge {
    EdgeCostType cost;
    VertexWrapper<Edge> source;
    VertexWrapper<Edge> dest;
};


using myEdge = Edge<double, Vertex>;
using myVertex = Vertex<myEdge>;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
2

yours simply works.. (but i don't know how to print and initialize member vector)

#include <vector>
#include <iostream>  
using namespace std;

template<typename EdgeType>
struct Vertex {
    vector<EdgeType> successors;
};

template<typename EdgeCostType, typename VertexWrapper>
struct Edge {
    EdgeCostType cost;
    VertexWrapper source;
    VertexWrapper dest;
};

int main (){

    Vertex<int> vertx = {{5}};
    Edge<int, decltype(vertx)> ed = {7};

    cout<< ed.cost <<"\n";     //cout<< ed.dest.successors<<"\n";   // not work, ask help!
}
0

Jarod42's answer will work, but it does constrain you to only doubles. If you want a more flexible one that accepts ints, for instance, you also have this option:

template<class T>
using myEdge = Edge<T, Vertex>;

template<class T>
using myVertex = Vertex<myEdge<T>>;

This will allow you to use other types of numbers, if for some reason you need a shorthand for that. Then using doubles would look like this:

myVertex<double> v;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    It was just an example usage. To go further, I would do `template struct graph_type { using egde = Edge; using vertex = Vertex; };` – Jarod42 Jan 01 '20 at 18:49