我正在编写一个Graph类,我想提供具有相同类的多种类型的图形。更具体地说,我想考虑有向或无向图,以及顶点(和边)有值的可能性。
现在,我的班级看起来像那样。
template<typename VertexValue = void, typename EdgeValue = void, bool directed = false>
class Graph {
public:
struct Vertex;
using Edge = Vertex::Edge;
Graph() = default;
//void addVertex(const VertexValue& vertex);
private:
std::vector<Vertex> m_vertices;
};
为方便起见,我将跳过与边缘实现相关的任何内容。
我现在要做的是&#34;专注&#34; Vertex类提供 - 或不提供 - 一个值,以及不同的方法,具体取决于图形是否是定向的。我希望能够执行以下操作(注意:顶点方法仅用于说明目的,Vertex的有向和无向版本具有不同的方法)。
template<typename VertexValue = void, bool directed = false>
class Graph {
public:
struct Vertex;
private:
std::vector<Vertex> m_vertices;
};
// Directed, with value
template<typename VertexValue, bool directed>
struct Graph<VertexValue, directed>::Vertex {
using ValueType = VertexValue;
EdgeIterator inEdges();
EdgeIterator outEdges();
ValueType value;
};
// Directed, without value
template<bool directed>
struct Graph<void, directed>::Vertex {
using ValueType = void;
EdgeIterator inEdges();
EdgeIterator outEdges();
};
// Undirected, with value
template<typename VertexValue>
struct Graph<VertexValue, false>::Vertex {
using ValueType = VertexValue;
EdgeIterator edges();
ValueType value;
};
// Undirected, without value
template<>
struct Graph<void, false>::Vertex {
using ValueType = void;
EdgeIterator edges();
};
不幸的是,为了做到这一点,我必须专门研究整个Graph类。所以我尝试了其他的东西:将Vertex类作为模板,并转发外部模板参数。
template<typename VertexValue = void, bool directed = false>
class Graph {
public:
template<typename Value, bool, typename dummy = void>
struct Vertex;
private:
std::vector<Vertex<VertexValue, directed>> m_vertices;
};
// Directed, with value
template<typename VertexValue, bool directed>
template<typename Value, bool, typename dummy>
struct Graph<VertexValue, directed>::Vertex {
using ValueType = Value;
EdgeIterator inEdges();
EdgeIterator outEdges();
ValueType value;
};
// Directed, without value
template<typename VertexValue, bool directed>
template<bool directed_, typename dummy>
struct Graph<VertexValue, directed>::Vertex<void, directed_, dummy> {
using ValueType = void;
EdgeIterator inEdges();
EdgeIterator outEdges();
};
// Undirected, with value
template<typename VertexValue, bool directed>
template<typename Value, typename dummy>
struct Graph<VertexValue, directed>::Vertex<Value, false, dummy> {
using ValueType = Value;
EdgeIterator edges();
ValueType value;
};
// Undirected, without value
template<typename VertexValue, bool directed>
template<typename dummy>
struct Graph<VertexValue, directed>::Vertex<void, false, dummy> {
using ValueType = void;
EdgeIterator edges();
};
这会奏效;但是,我不喜欢转发模板参数的想法,它还引入了一个负担,即虚拟模板参数。我还想过在Graph类之外定义Vertex类,如下所示:
template<typename ValueType, bool directed>
class GraphVertex {
EdgeIterator inEdges();
EdgeIterator outEdges();
ValueType value;
};
// Specializations...
template<typename Vertex = GraphVertex<void, false>>
class Graph {
public:
// ...
private:
std::vector<Vertex> m_vertices;
};
......甚至是那样:
template<typename ValueType, bool directed>
class GraphVertex {
EdgeIterator inEdges();
EdgeIterator outEdges();
ValueType value;
};
// Specializations...
template<typename VertexValue = void, bool directed = false>
class Graph {
public:
// ...
private:
std::vector<GraphVertex<VertexValue, directed>> m_vertices;
};
...但我更喜欢嵌套类的想法,其中Vertex类确实是Graph类的属性。另外,即使这三种解决方案中的解决方案仍然有我的偏好,我也没有找到任何其他名称&#34; GraphVertex&#34;。它困扰着我。
最后,这是我的问题。有没有其他方法可以做我想要的(即提供不同的Vertex类 - 或功能 - 取决于Graph模板参数)?如果是这样,那么优势如何?如果没有,我应该更喜欢什么?为什么?
答案 0 :(得分:0)
您的第一次实施不可能直接实现,因为:
C ++ 11标准的第14.5.5.3/1段
[...]类模板特化是一个独特的模板。类模板部分特化的成员与主模板的成员无关。 [...]
这意味着成员struct Vertex
不需要存在于类Graph
的部分模板特化中,因此不能直接定义,而不需要专门化整个类。
所以,你不能做类似的事情:
template<typename T1, typename T2>
class Graph { struct Vertex; };
template<typename T2>
struct Graph<double, T2>::Vertex { };
(另见Template class incomplete specialization)
C ++ 11标准的第14.7.3 / 15段
成员或成员模板可以嵌套在许多封闭的类模板中。在对此类成员的明确专门化中,成员声明前面应有一个
template<>
,用于明确专门化的每个封闭类模板
(另请参阅IdeaHat所示的Specializing inner template with default parameters)
这意味着:
template<typename VertexValue = void, bool directed = false>
struct Graph {
struct Vertex;
};
// template implementation
template<typename VertexValue, bool directed>
struct Graph<VertexValue, directed>::Vertex {
using ValueType = VertexValue;
};
// full specialization
template<>
struct Graph<void, false>::Vertex {
using ValueType = void;
};
工作正常。
一种可能的解决方案是将您想要专门化的所有类型放入Graph
的基类中,然后完全专门化这个基类:
template<typename VertexValue, bool directed>
struct BaseGraph;
template<typename VertexValue = void, bool directed = false,
typename Base = BaseGraph<VertexValue, directed> >
struct Graph : public Base {
using Vertex = typename Base::Vertex;
};
// Directed, with value
template<typename VertexValue, bool directed>
struct BaseGraph {
struct Vertex {
using ValueType = VertexValue;
};
};
// Directed, without value
template<bool directed>
struct BaseGraph<void, directed> {
struct Vertex {
using ValueType = void;
};
};
// Undirected, with value
template<typename VertexValue>
struct BaseGraph<VertexValue, false> {
struct Vertex {
using ValueType = VertexValue;
};
};
// Undirected, without value
template<>
struct BaseGraph<void, false> {
struct Vertex {
using ValueType = void;
};
};
但这与您使用外部GraphVertex类的方法非常相似,我更喜欢。