Consider the following setup:
template< typename Held >
class Node{
//...
};
template< typename Held >
class vNode{
//...
};
template <typename... Graphs>
class Branch{
//...
};
template <typename...> class Graph; // undefined
template<
typename node_t
> class Graph< node_t >{ //specialization for an ending node
//...
};
template<
typename node_t,
typename... Graphs
> class Graph< node_t, Branch< Graphs...> >{ //specialization for a mid-graph node
//...
};
template<
template <typename> class node_t,
typename Held
> void f( Graph< Node<Held> > ) {
//stuff A on a node
}
template<
template <typename> class node_t,
typename Held
> void f( Graph< const Node<Held> > ) {
//stuff A on a const node
}
template<
template <typename> class node_t,
typename Held
> void f( Graph< vNode<Held> > ) {
//stuff B on a virtual node
}
template<
template <typename> class node_t,
typename Held
> void f( Graph< const vNode<Held> > ) {
//stuff B on a virtual const node
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f( Graph< Node<Held>, Branch<Graphs...>> ) {
//stuff C on a node with a branch
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f( Graph< const Node<Held>, Branch<Graphs...> > ) {
//stuff C on a const node with a branch
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f( Graph< vNode<Held>, Branch<Graphs...> > ) {
//stuff D on a virtual node with a branch
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f( Graph< const vNode<Held>, Branch<Graphs...> > ) {
//stuff D on a virtual const node with a branch
}
In other words - I'm creating a type that represents a graph. Nodes can be normal, or virtual, const and non-const. A Graph can contain a single node, or a node and a branch of graphs.
When I create a function f
I want it to be const-neutral (do the same stuff on a const and non-const version of a node in a graph, but different on branched and unbranched graphs). Do I have to:
Use std::enable_if
hack?
Is there a smarter solution to the problem that will make f
accept const and non-const nodes?
Instead of using a template template parameter and have a gazillion overloads, just use a type template parameter:
template<class T> void f( Graph<T> ) { /*...*/ }
T
will be deduced to be Node<Foo>
, vNode<Foo>
or const Node<Foo>
etc. as appropriate. If Node
vs vNode
matters, you can always extract the type of the node with a simple trait class. Similarly, you can use static_assert
together with a trait class to ensure that T
is a specialization of Node
or vNode
.