C++ 还有一个模板循环依赖性问题
我试图创建一个基于面向对象模板的通用图结构,但是在我的设计中,我遇到了一个可能的循环依赖,我不知道如何避免 我将顶点和边类定义如下:C++ 还有一个模板循环依赖性问题,c++,templates,metaprogramming,circular-dependency,C++,Templates,Metaprogramming,Circular Dependency,我试图创建一个基于面向对象模板的通用图结构,但是在我的设计中,我遇到了一个可能的循环依赖,我不知道如何避免 我将顶点和边类定义如下: template <class label_type, class edge_type> class basic_vertex { .. } template <class vertex_type, class weight_type = std::int32_t> class basic_edge { .. } class basic
template <class label_type, class edge_type>
class basic_vertex { .. }
template <class vertex_type, class weight_type = std::int32_t>
class basic_edge { .. }
class basic_vertex;
模板
类基本_顶点{..}
模板
类基本_边{..}
在vertex类中,我通过将指向节点的指针存储在std::list中来跟踪连接到节点的内边和外边
在edge对象中,我保留了两个表示源顶点和目标顶点的引用
如果我要填充顶点模板参数,我需要知道边的类型。为了知道边的类型,我需要知道顶点的类型
您知道如何解决这个问题吗?您可以在使用类解决循环依赖关系之前预先声明一个类,如下所示:
template <class label_type, class edge_type>
class basic_vertex { .. }
template <class vertex_type, class weight_type = std::int32_t>
class basic_edge { .. }
class basic_vertex;
您可以在使用类解决循环依赖关系之前预先宣布该类,如下所示:
template <class label_type, class edge_type>
class basic_vertex { .. }
template <class vertex_type, class weight_type = std::int32_t>
class basic_edge { .. }
class basic_vertex;
不管它是否是模板,它与类的循环依赖性问题是相同的。您的一个类必须能够使用指向另一个类的指针/引用。 前向声明类边缘; 在基本顶点中使用边*
在边中使用基本顶点无论是否使用其模板,它与类的循环依赖性问题是相同的。您的一个类必须能够使用指向另一个类的指针/引用。 前向声明类边缘; 在基本顶点中使用边*
使用“边中的基本顶点”有一种解决方案可以解决类模板之间的相互依赖关系。但在考虑它之前,我通常会问自己:“我不应该把它解耦吗?”事实上,这可能是一个糟糕的设计。但有时,它是模型的一部分。你的案例,图表,就是一个例子 该解决方案基于概念级的解耦,并引入了一个中间模板类型,该模板类型将嵌入和了解两种类型(顶点和边),并打破循环
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;
}
模板
结构顶点{
typedef typename T_图::edge_T edge_T;
边缘_t*边缘;
//……也许还有更多的边缘。。。。
};
模板
结构边缘\u tmpl{
typedef typename T_图::顶点T顶点T;
顶点_t*顶点;
};
模板<模板类T_顶点,
模板类T_边,
typename T_weight=int,
typename T_label=int>
结构图{
typedef graph_tmpl自;
类型定义T_顶点T;
typedef T_edge T;
};
int main(){
typedef graph\u tmpl<顶点\u tmpl,边\u tmpl>图形;
typedef typename图形\u t::edge\u t basic\u edge;
typedef typename图形\u t::顶点\u t基本顶点;
基本边;
基本顶点;
vertex.edge=&edge;
edge.vertex=&vertex;
}
您将在中找到解决方案的详细说明。有一种解决方案可以解决类模板之间的相互依赖关系。但在考虑它之前,我通常会问自己:“我不应该把它解耦吗?”事实上,这可能是一个糟糕的设计。但有时,它是模型的一部分。你的案例,图表,就是一个例子 该解决方案基于概念级的解耦,并引入了一个中间模板类型,该模板类型将嵌入和了解两种类型(顶点和边),并打破循环
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;
}
模板
结构顶点{
typedef typename T_图::edge_T edge_T;
边缘_t*边缘;
//……也许还有更多的边缘。。。。
};
模板
结构边缘\u tmpl{
typedef typename T_图::顶点T顶点T;
顶点_t*顶点;
};
模板<模板类T_顶点,
模板类T_边,
typename T_weight=int,
typename T_label=int>
结构图{
typedef graph_tmpl自;
类型定义T_顶点T;
typedef T_edge T;
};
int main(){
typedef graph\u tmpl<顶点\u tmpl,边\u tmpl>图形;
typedef typename图形\u t::edge\u t basic\u edge;
typedef typename图形\u t::顶点\u t基本顶点;
基本边;
基本顶点;
vertex.edge=&edge;
edge.vertex=&vertex;
}
您可以在中找到解决方案的详细说明。您能解释一下为什么要使用模板吗?@alestanis:我正试图让它尽可能的通用和快速。我正试图让它尽可能的通用和快速:模板不是神奇的编程灰尘,它让事情变得更快。就泛型而言,这听起来像是过早的优化。那么,你为什么要使用模板呢?@DavidHammen好吧,我希望顶点的标签能够根据用例进行调整。有时我可能希望它是一个数字,而有时我可能希望它是一个字符串,甚至是一些自定义类。我还计划扩展基本版本,以允许在其中嵌入数据结构。例如我可能会在节点中嵌入地理坐标以及关于哪种类型的汽车可以通过边缘的信息。边缘的重量类型也是如此:有时我可能希望它是整数,而其他时候我可能需要它是双精度或自定义数字类型。你能解释一下为什么要使用模板吗?@alestanis:我正在尝试将其设置为通用的,尽可能快。我正试图使它尽可能通用,尽可能快:模板不是神奇的编程灰尘,使事情更快。就泛型而言,这听起来像是过早的优化。那么,你为什么要使用模板呢?@DavidHammen好吧,我希望顶点的标签能够根据用例进行调整。有时我可能希望它是一个数字,而有时我可能希望它是一个字符串,甚至是一些自定义类。我还计划扩展基本版本,以允许在其中嵌入数据结构。例如,我可能会在节点中嵌入地理坐标,以及关于哪种类型的汽车可以通过边缘的信息。边缘的权重类型也是如此:有时我可能希望它是int,而有时我可能希望它是ne