I have some graph classes that can inherit from each other to provide the functionality needed in different cases (directed graph, traversable graph, nested graph, etc).
In order to make it possible to use the final derived types, these are provided as template arguments to the base classes. This way, for instance Edge::GetSource can return the derived class Node, and not the base class Node.
To make things simple, the graph classes take only one template argument: GraphTypes. GraphTypes in turn takes as template arguments all the needed derived graph classes. This makes it very easy to make changes to the types used in the graph classes, as only GraphTypes need to be changed.
template<class GraphT, class NodeT, class EdgeT>
class GraphTypes {
public:
using GraphType = GraphT;
using NodeType = NodeT;
using EdgeType = EdgeT;
}; // GraphTypes
template<class GraphTypes>
class Edge {
private:
using GraphType = typename GraphTypes::GraphType;
using NodeType = typename GraphTypes::NodeType;
using EdgeType = typename GraphTypes::EdgeType;
public:
NodeType &GetSource();
protected:
NodeType *m_pSource;
}; // Edge
template<class GraphTypes>
inline NodeType &Edge<GraphTypes>::GetSource() {
return *m_pSource;
} // Edge::GetSource
This is working great! But now I want to add an optional Context argument. In some cases, a context object needs to passed around while working on the graph and be made aware, for instance, when Edge::SetSource is called.
My idea is to add a variadic template argument. This way graph classes that need no context can just omit it. But how can I add a variadic template argument to GraphTypes and then use it inside the other graph classes that have GraphTypes as an template argument?
template<class GraphT, class NodeT, class EdgeT, class ...ContextT>
class GraphTypes {
public:
// error C3520: 'ContextT': parameter pack must be expanded in this context
using ContextType = ContextT;
}; // GraphTypes
template<class GraphTypes>
class Edge {
private:
using ContextType = typename GraphTypes::ContextType;
public:
// error C3543: 'GraphTypes::ContextType': does not contain a parameter pack
void SetSource(NodeType &Source, ContextType &...Context);
}; // Edge
template<class GraphTypes>
void Edge<GraphTypes>::SetSource(NodeType &Source, ContextType &...Context) {
if(&Source == m_pSource)
return;
// I think this should work, but open to suggestions ;)
std::initializer_list<bool>{ (Context.PreSetSource(*this), true)... };
m_pSource = &Source;
std::initializer_list<bool>{ (Context.PostSetSource(*this), true)... };
} // Edge::SetSource