Reputation: 63
I'm trying to develop 2 classes, Node and Connection, but I don't have experience in C++ or C++ templates.
The Node contains a list of connections and a Connection contains 2 nodes. So I suppose that a node has a template parameter that specifies which type of connections are in the list and that a connection has a template parameter that specifies which kind of nodes it contains.
How can I enforce in C++ that the node contains connections of a generic type but that these connections contain nodes of the class Node? The same question for the Connection class. I want to have a generic parameter for the type of the nodes, but these generic nodes must contain a list with connections of the Connection class.
I've tried several things, this is what I have at the moment:
template <template <template <class Conn> class Node> class Conn>
class Node {
};
Can someone help me?
Thanks in advance,
Jef
Upvotes: 3
Views: 239
Reputation: 2393
Assuming that you want different types of Nodes, but that Connections are nothing but a link between two Nodes (that is, that you don't need to do any specialisation on the Connections) then you could do something like:
template <class Node>
class Connection
{
Node& node1;
Node& node2;
};
template <class Node>
class NodeBase
{
std::list< Connection<Node> > connections;
};
// example concrete node
class MassNode : public NodeBase<MassNode>
{
// stuff that makes a mass node more than just a node.
}
This is a pattern called the curiously recurring template pattern.
There are other ways of attacking this - can you give more info on your specific problem domain?
EDIT to show intrusive vs non-intrusive techniques
namespace intrusive
{
template <class node>
class directedConnection
{
node& From;
node& To;
};
template <class node>
class directedGraphNode
{
private:
std::set< directedConnection<node>* > OutgoingConnections;
std::set< directedConnection<node>* > IncomingConnections;
};
// sample concrete class. Note that it is a graph node AND it contains the node data.
class bayesianNetworkNode : public directedGraphNode<bayesianNetworkNode>
{
public:
double Probabilities[16];
};
bayesianNetworkNode B1, B2, B3;
}
namespace non_intrusive
{
template <class T>
class undirectedGraphNode;
template <class T>
class undirectedConnection
{
undirectedGraphNode<typename T>& Node1;
undirectedGraphNode<typename T>& Node2;
};
template <class T>
class undirectedGraphNode
{
private:
std::set< undirectedConnection<T>* > Connections;
T Value;
public:
T& operator * () { return Value; }
T* operator -> () { return &Value; }
};
// sample concrete class. Note that this class contains the node data, but is NOT actually a graph node itself.
// It is "pointed to" by a node in the same way that an STL iterator "points to" a collection item.
class markovNetworkNode
{
public:
std::set<formula> Formulae;
};
undirectedGraphNode<markovNetworkNode> M1, M2, M3;
}
Upvotes: 3