我有两个表示图形的类:
class Node {
public:
void AppendSource(Edge &Edge) { m_Sources.append(&Edge); }
void AppendSink(Edge &Edge) { m_Sinks.append(&Edge); }
QList<Edge *> &Sources() { return m_Sources; }
QList<Edge *> &Sinks() { return m_Sinks; }
QList<Edge *> const &Sources() const { return m_Sources; }
QList<Edge *> const &Sinks() const { return m_Sinks; }
protected:
QList<Edge *> m_Sources;
QList<Edge *> m_Sinks;
}; // Node
class Edge {
public:
Edge(Node &Source, Node &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
Node const &Source() const { return *m_pSource; }
Node const &Sink() const { return *m_pSink; }
Node &Source() { return *m_pSource; }
Node &Sink() { return *m_pSink; }
void SetSource(Node &Source) { m_pSource = &Source; }
void SetSink(Node &Sink) { m_pSink = &Sink; }
protected:
Node *m_pSource;
Node *m_pSink;
}; // Edge
应该可以从这些类继承,以便为特定类型的图添加功能。因此,这些类应该是模板类:
template <class EDGE_TYPE>
class Node {
public:
void AppendSource(EDGE_TYPE &Edge) { m_Sources.append(&Edge); }
void AppendSink(EDGE_TYPE &Edge) { m_Sinks.append(&Edge); }
QList<EDGE_TYPE *> &Sources() { return m_Sources; }
QList<EDGE_TYPE *> &Sinks() { return m_Sinks; }
QList<EDGE_TYPE *> const &Sources() const { return m_Sources; }
QList<EDGE_TYPE *> const &Sinks() const { return m_Sinks; }
protected:
QList<EDGE_TYPE *> m_Sources;
QList<EDGE_TYPE *> m_Sinks;
}; // Node
template <class NODE_TYPE>
class Edge {
public:
Edge(NODE_TYPE &Source, NODE_TYPE &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
NODE_TYPE const &Source() const { return *m_pSource; }
NODE_TYPE const &Sink() const { return *m_pSink; }
NODE_TYPE &Source() { return *m_pSource; }
NODE_TYPE &Sink() { return *m_pSink; }
void SetSource(NODE_TYPE &Source) { m_pSource = &Source; }
void SetSink(NODE_TYPE &Sink) { m_pSink = &Sink; }
protected:
NODE_TYPE *m_pSource;
NODE_TYPE *m_pSink;
}; // Edge
但是现在看来,不再扩展类就无法使用这些类!尝试进行一些带有明显对应错误的尝试:
new Node(); // 'Node': use of class template requires template argument list
new Node<>(); // 'Node': too few template arguments
new Node<Edge>(); // 'Edge': unspecialized class template can't be used as a template argument for template parameter 'EDGE_TYPE', expected a real type
new Node<Edge<>>(); // 'Edge': too few template arguments
new Node<Edge<Node>>(); // 'Node': unspecialized class template can't be used as a template argument for template parameter 'NODE_TYPE', expected a real type
new Node<Edge<Node<>>>(); // 'Node': too few template arguments
我希望通过为模板参数引入默认值来解决此问题。尝试一些相应的错误:
template <class EDGE_TYPE = Edge>
class Node { ... }
template <class NODE_TYPE = Node>
class Edge { ... }
new Node<>(); // 'Edge': unspecialized class template can't be used as a template argument for template parameter 'EDGE_TYPE', expected a real type
template <class EDGE_TYPE = Edge<>>
class Node { ... }
template <class NODE_TYPE = Node<>>
class Edge { ... }
new Node<>(); // recursive type or function dependency context too complex
template <class EDGE_TYPE = Edge<Node<EDGE_TYPE>>>
class Node { ... }
template <class NODE_TYPE = Node<Edge<NODE_TYPE>>>
class Edge { ... }
new Node<>(); // 'EDGE_TYPE': undeclared identifier
如何通过继承使Node
和Edge
直接可用和可扩展?
答案 0 :(得分:3)
如何使Node和Edge既直接可用又可扩展 虽然继承?
我将以粗体显示该要求。
尽管可以使Edge和Node的定义相互依赖,但无法进行Edge和Node的重复声明,因为这样的声明将产生无限模板递归:
Node<> = Node<Edge<>> = Node<Edge<Node<>>> = Node<EdgeNode<Edge<>>>> ...
因此,如果您希望Edge<>
和Node<>
直接可用(即在不创建虚拟派生类的情况下可实例化),则应该中断该递归。例如,通过使Edge
和Node
都依赖于某些第三性状类:
// Forward declaration.
struct DefaultGraphTypes;
template <typename GraphTypes = DefaultGraphTypes>
struct Node;
template <typename GraphTypes = DefaultGraphTypes>
struct Edge;
// Traits class.
template <typename NodeT, typename EdgeT>
struct GraphTypes
{
// Could change this to 'using' in modern C++
typedef NodeT FinalNodeType;
typedef EdgeT FinalEdgeType;
// typedef MayBeSomeOtherParameters ...
};
struct DefaultGraphTypes
: public GraphTypes<Node<DefaultGraphTypes>, Edge<DefaultGraphTypes>>
{
};
// Implementation of graph classes.
template <typename GraphTypes>
struct Node
{
typedef typename GraphTypes::FinalNodeType FinalNodeType;
typedef typename GraphTypes::FinalEdgeType FinalEdgeType;
// ... Your implementation
};
template <typename GraphTypes>
struct Edge
{
typedef typename GraphTypes::FinalNodeType FinalNodeType;
typedef typename GraphTypes::FinalEdgeType FinalEdgeType;
// ... Your implementation
};
// User-derived types.
struct MyNode;
struct MyEdge;
struct MyNode
: public Node<GraphTypes<MyNode, MyEdge>>
{
// Something specific
};
struct MyEdge
: public Edge<GraphTypes<MyNode, MyEdge>>
{
// Something specific
};
// Test
int main()
{
Node<> n1;
Edge<> e1;
MyNode n2;
MyEdge e2;
return 0;
}
答案 1 :(得分:0)
恕我直言,这可以通过在正确的位置插入前向声明来实现。我使用了OP示例代码的一部分,并将其完成为可编译的示例:
let activityController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)
activityController.excludedActivityTypes = [.print, .mail, .airDrop, .assignToContact, .copyToPasteboard, .addToReadingList, .markupAsPDF, .message, .openInIBooks, .postToTwitter, .postToFacebook]
present(activityController, animated: true, completion: nil)
那是实际的把戏:
在#include <iostream>
#include <vector>
#define QList std::vector // Sorry, no Qt at hand in coliru
template <class EDGE_TYPE>
class Node {
public:
void AppendSource(EDGE_TYPE &Edge) { m_Sources.append(&Edge); }
void AppendSink(EDGE_TYPE &Edge) { m_Sinks.append(&Edge); }
QList<EDGE_TYPE *> &Sources() { return m_Sources; }
QList<EDGE_TYPE *> &Sinks() { return m_Sinks; }
QList<EDGE_TYPE *> const &Sources() const { return m_Sources; }
QList<EDGE_TYPE *> const &Sinks() const { return m_Sinks; }
protected:
QList<EDGE_TYPE *> m_Sources;
QList<EDGE_TYPE *> m_Sinks;
}; // Node
template <class NODE_TYPE>
class Edge {
public:
Edge(NODE_TYPE &Source, NODE_TYPE &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
NODE_TYPE const &Source() const { return *m_pSource; }
NODE_TYPE const &Sink() const { return *m_pSink; }
NODE_TYPE &Source() { return *m_pSource; }
NODE_TYPE &Sink() { return *m_pSink; }
void SetSource(NODE_TYPE &Source) { m_pSource = &Source; }
void SetSink(NODE_TYPE &Sink) { m_pSink = &Sink; }
protected:
NODE_TYPE *m_pSource;
NODE_TYPE *m_pSink;
}; // Edge
// forward declarations:
struct WNode;
struct WEdge;
// declaration of derived types
struct WNode: public Node<WEdge>
{
int weight;
};
struct WEdge: public Edge<WNode>
{
int weight;
WEdge(WNode &src, WNode &snk): Edge(src, snk) { }
};
// check whether it compiles
int main()
{
WNode node1, node2;
WEdge edge12(node1, node2);
// done
return 0;
}
和template class Node
中仔细使用的OP仅引用和指向相应的指针。相反类型。因此,在两种情况下,不完整的类型都足以用作模板参数。这些不完整的类型由正向声明提供:
template class Edge
然后,可以从// forward declarations:
struct WNode;
struct WEdge;
和WNode
派生类WEdge
和Node<WEdge>
。
答案 2 :(得分:0)
模板模板参数可能会有所帮助:
template <typename TEdge>
class Node {
public:
using EDGE_TYPE = TEdge;
void AppendSource(EDGE_TYPE &Edge) { m_Sources.append(&Edge); }
void AppendSink(EDGE_TYPE &Edge) { m_Sinks.append(&Edge); }
QList<EDGE_TYPE *> &Sources() { return m_Sources; }
QList<EDGE_TYPE *> &Sinks() { return m_Sinks; }
QList<EDGE_TYPE *> const &Sources() const { return m_Sources; }
QList<EDGE_TYPE *> const &Sinks() const { return m_Sinks; }
protected:
QList<EDGE_TYPE *> m_Sources;
QList<EDGE_TYPE *> m_Sinks;
}; // Node
template <template <typename> class TNode>
class Edge {
public:
using NODE_TYPE = TNode<Edge>; // which is TNode<Edge<TNode>>
Edge(NODE_TYPE &Source, NODE_TYPE &Sink) : m_pSource(&Source), m_pSink(&Sink) {}
NODE_TYPE const &Source() const { return *m_pSource; }
NODE_TYPE const &Sink() const { return *m_pSink; }
NODE_TYPE &Source() { return *m_pSource; }
NODE_TYPE &Sink() { return *m_pSink; }
void SetSource(NODE_TYPE &Source) { m_pSource = &Source; }
void SetSink(NODE_TYPE &Sink) { m_pSink = &Sink; }
protected:
NODE_TYPE *m_pSource;
NODE_TYPE *m_pSink;
};
那么您可能会有:
using MyEdge = Edge<Node>;
using MyNode = Node<Edge<Node>>; // Node<MyEdge>
甚至:
template <template <typename> class TNode>
class CustomEdge : Edge<TNode> {
// ...
};
using MyNode2 = Node<CustomEdge>;
using MyEdge2 = CustomEdge<Node>;