Циклическая зависимость шаблонов вариативных шаблонов классов

Я пытаюсь построить «нецентрализованную» структуру графа, в которой узлы и ребра пересекаются. Примерно так: Справочная структура кругового шаблона.

Хотя я пытаюсь поддержать, что узлы могут содержать несколько типов ребер разной «арности». И это, в свою очередь, множество типов узлов ребра.

¿Есть ли способ добиться этого с помощью универсального программирования/метапрограммирования без использования наследования?

Следующий подход, который я пробовал, подчеркивает проблему:

#include <iostream>
#include <tuple>
#include <list>

using namespace std;

template<class ...EdgeTypes>
class node
{
  public:
    std::tuple<std::list<EdgeTypes*>...> edges_;

    template<size_t I>
    using container_value_type_i = typename std::tuple_element<I, decltype(edges_) >::type::value_type;

    template< std::size_t I>
    void addEdge(const container_value_type_i<I>& e)
    { std::get<I>(edges_).push_back(e); }
};

template<template<class...> class ...V>
class edge
{

  public:

    std::tuple<V<edge>*...> vertices_;
    //           ^^^^
    // its forcing that all nodes have the same number of 'edges types' (one)
    // and that they are of the same 'arity' as edge object

    template<size_t I>
    using vertex_type_i = typename std::tuple_element<I, decltype(vertices_) >::type;

    template< std::size_t I>
    void addNode(const vertex_type_i<I>& e)
    { std::get<I>(vertices_) = e; }

};

int main()
{
  edge<node> unary_edge;
  edge<node, node> binary_edge;

  node<edge<node>> unary_node_of_unary_edges;

  unary_node_of_unary_edges.addEdge<0>(&unary_edge);
  unary_edge.addNode<0>(&unary_node_of_unary_edges);

  node<edge<node, node>> unary_node_of_binary_edges;

  unary_node_of_binary_edges.addEdge<0>(&binary_edge);

  // This won't compile as edge type of node's edges are not the same as unary_edge
  //unary_edge.addNode<0>(unary_node_of_binary_edges);

  node<edge<node>, edge<node, node>> binary_node_of_unary_edges_and_binary_edges;

  binary_node_of_unary_edges_and_binary_edges.addEdge<0>(&unary_edge);
  binary_node_of_unary_edges_and_binary_edges.addEdge<1>(&binary_edge);

  // This won't compile as nodes's edges are not all the same type
  //unary_edge.addNode<0>(&binary_node_of_unary_edges_and_binary_edges);
  return 0;
}

person CaTo    schedule 28.03.2018    source источник


Ответы (1)


Вы можете закодировать всю структуру airity графа в системе типов, но я сомневаюсь, что это полезно.

Стирание типа всегда возможно. Игнорируя это, вы можете использовать шаблоны как для типа ребра, так и для типа узла, а также для максимальной воздушности.

template<template<class...>class Z>
struct ztemplate{
  template<class...Ts>
  using z=Z<Ts...>;
};
template<class zE, class Indexes>
class Node;
using zNode=ztemplate<Node>;
template<class zN, class Indexes, class Count>
class Edge;
using zEdge=ztemplate<Edge>;

template<class zE, std::size_t...Is>
class Node<zE,std::index_sequence<Is...>>{
  std::tuple< std::list< zE::template z<zNode, std::index_sequence<Is...>, std::integral_constant<std::size_t,Is>>... > edges;
};
template<class zN, std::size_t...Is, std::size_t A>
class Edge<zN,std::index_sequence<Is...>, std::integral_constant<std::size_t,A>>{
  std::array< zN::template z<zEdge, std::index_sequence<Is...>>*, A> nodes;
};

или что-то в этом роде.

person Yakk - Adam Nevraumont    schedule 28.03.2018
comment
какой зверь, мне понадобилось немного, чтобы получить его. Хотя «арность узлов» ребра должна быть одинаковой (используется массив). Есть ли способ, которым ребро принимает узлы разной арности? Может быть, шаблон, объединяющий zN и Is вместе? - person CaTo; 30.03.2018
comment
@cato проблема в том, что вам быстро требуется вся структура графа для определения типов каждого узла без какой-либо смазки для стирания типа. Мы обеспечиваем это, используя максимальную воздушность в списках, допускающих значение NULL. Есть и другие места, где вместо этого можно применить стирание текста. - person Yakk - Adam Nevraumont; 30.03.2018