Use Current Template as a Template Parameter to one of the Template Parameters
Asked Answered
B

3

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;
};
Battement answered 31/12, 2019 at 23:41 Comment(5)
template <typename> class VertexWrapper? Also, why do you have both C++11 and C++17 tags? Which standard are you targeting?Goldberg
@Goldberg Afaik both apply, should I only use the most recent one? Also I'm not sure what you mean by template <typename> typename VertexWrapperBattement
Is the VertexWrapper type argument always supposed to be of the form std::shared_ptr<decltype(v)> or some_template_here<decltype(v)>?Nakamura
@Nakamura it should be something like shared_ptr/unique_ptr/something with operator->Battement
If I'm reading this question right, you might want to look into "template template" parameters #214261Halfdan
C
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>;
Commitment answered 1/1, 2020 at 0:0 Comment(1)
Thanks! TIL about template template parametersBattement
C
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!
}
Cotyledon answered 1/1, 2020 at 0:43 Comment(0)
M
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;
Monterrey answered 1/1, 2020 at 6:30 Comment(1)
It was just an example usage. To go further, I would do template <typename T> struct graph_type { using egde = Edge<T, Vertex>; using vertex = Vertex<edge>; };Commitment

© 2022 - 2024 — McMap. All rights reserved.