【问题标题】:Yet another template circular dependency issue另一个模板循环依赖问题
【发布时间】:2012-12-10 12:20:22
【问题描述】:

我正在尝试创建一个基于通用图形结构的面向对象模板,但是在我的设计中我遇到了一个可能的循环依赖,我不确定如何避免。

我将我的顶点和边类定义如下:

template <class label_type, class edge_type>
class basic_vertex { .. }

template <class vertex_type, class weight_type = std::int32_t>
class basic_edge { .. }

在顶点类中,我通过将指向它们的指针存储在 std::list 中来跟踪连接到节点的内边和外边。

在边缘对象中,我保留了 2 个引用来表示源顶点和目标顶点。

如果我要填写顶点模板参数,我需要知道边的类型。为了知道边的类型,我需要知道顶点的类型。

知道如何解决这个问题吗?

【问题讨论】:

  • 您能解释一下为什么要使用模板吗?
  • @alestanis:我正在尝试使其尽可能通用且尽可能快。
  • Re 我正在努力使其尽可能通用且尽可能快:模板并不是让事情变得更快的神奇编程灰尘。就通用性而言,这听起来像是过早的优化。再说一遍,你为什么要使用模板?
  • @DavidHammen 好吧,我希望根据用例调整顶点的标签。有时我可能希望它是一个数字,而其他时候我可能希望它是一个字符串,甚至是一些自定义类。我还计划扩展基本版本,以便在其中嵌入数据结构。例如,我可能会在节点中嵌入地理坐标以及关于什么类型的汽车可以通过边缘的信息。
  • 边缘的权重类型也是如此:有时我可能希望它是 int 而其他时候我可能需要它是 double 或自定义数字类型。

标签: c++ templates metaprogramming circular-dependency


【解决方案1】:

有一种解决方案可以解决类模板之间的相互依赖关系。但在考虑之前,我通常会问自己:“我不应该解耦吗?”事实上,这可能是一个糟糕的设计。但有时,它是模型的一部分。您的情况,图表就是一个例子。

该解决方案基于概念级别的解耦,并引入一个中间模板类型,该模板类型将嵌入并知道两种类型(顶点和边)a 并打破循环。

template <typename T_graph, typename T_label>
struct vertex_tmpl {
    typedef typename T_graph::edge_t edge_t;
    edge_t* edge;
    // .... maybe some more edges ....
};

template <typename T_graph, typename T_weight>
struct edge_tmpl {
    typedef typename T_graph::vertex_t vertex_t;
    vertex_t* vertex;
};

template < template <typename, typename> class T_vertex,
           template <typename, typename> class T_edge,
           typename T_weight = int,
           typename T_label = int >
struct graph_tmpl {
    typedef graph_tmpl< T_vertex, T_edge> self_t;
    typedef T_vertex<self_t, T_label> vertex_t;
    typedef T_edge<self_t, T_weight> edge_t;
};

int main() {
    typedef graph_tmpl< vertex_tmpl, edge_tmpl> graph_t;
    typedef typename graph_t::edge_t basic_edge;
    typedef typename graph_t::vertex_t basic_vertex;

    basic_edge edge;
    basic_vertex vertex;
    vertex.edge = &edge;
    edge.vertex = &vertex;
}

http://ideone.com/FrBqcb

您可以在those very good lecture notes about advanced C++ technics 中找到对该解决方案的详细说明。

【讨论】:

    【解决方案2】:

    您可以在使用之前预先声明一个类以解决循环依赖问题,如下所示:

    class basic_vertex;
    

    【讨论】:

    • 恐怕这不适用于模板。编译器告诉我需要指定模板参数。
    【解决方案3】:

    不管它的模板与否,它与类的循环依赖相同的问题。您的一个类必须能够仅使用指向另一个类的指针/引用。 前向声明类 Edge; 在 basic_vertex 中使用 Edge* 在 Edge 中使用 basic_vertex

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多