Use o modelo atual como um parâmetro de modelo para um dos parâmetros de modelo

8

Estou tentando criar uma estrutura de gráfico genérica, mas estou enfrentando essa dependência circular entre vértices e arestas. Eu defino minhas classes Vertex e Edge da seguinte forma:

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

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

Eu gostaria de instanciar isso com algo do tipo Vertex<Edge<int, std::shared_ptr<decltype(v)>>> v;, mas obviamente não posso. O que posso fazer para resolver essa dependência circular?

Editar:

Eu acho que esse problema se resume em usar o modelo atual como um parâmetro de modelo para um dos parâmetros do modelo atual, por exemplo, como fazer algo assim:

template<typename VertexWrapper>
struct Vertex {
    std::vector<pair<int, VertexWrapper<Vertex>>> successors;
};
Simon Berens
fonte
2
template <typename> class VertexWrapper? Além disso, por que você tem as tags C ++ 11 e C ++ 17? Qual padrão você está alvejando?
HolyBlackCat
@HolyBlackCat Afaik se aplicam, devo usar apenas o mais recente? Também não tenho certeza do que você quer dizer comtemplate <typename> typename VertexWrapper
Simon Berens
O VertexWrapperargumento de tipo sempre deve ter a forma std::shared_ptr<decltype(v)>ou some_template_here<decltype(v)>?
noz
@walnut, deve ser algo como shared_ptr / unique_ptr / algo com operador-> #
6990 Simon Berens
Se estou lendo esta pergunta corretamente, convém consultar os parâmetros "modelo de modelo" stackoverflow.com/questions/213761/…
Joe

Respostas:

10

Com o parâmetro template template, você pode fazer algo como:

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
fonte
Obrigado! TIL sobre os parâmetros do modelo
Simon Berens
2

o seu simplesmente funciona .. (mas eu não sei como imprimir e inicializar o vetor de membro)

#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!
}
nonock
fonte
1
A idéia é ter um Vertex<Edge<double, Vertex</*..*/>>>...
Jarod42 01/01
0

A resposta de Jarod42 funcionará, mas a limita a dobrar. Se você quer um mais flexível que aceite ints, por exemplo, também tem esta opção:

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

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

Isso permitirá que você use outros tipos de números, se por algum motivo precisar de uma abreviação para isso. Em seguida, o uso de duplas ficaria assim:

myVertex<double> v;
Chipster
fonte
1
Foi apenas um exemplo de uso. Para ir mais longe, eu fariatemplate <typename T> struct graph_type { using egde = Edge<T, Vertex>; using vertex = Vertex<edge>; };
Jarod42 01/01