I'm implementing a tree where each Node
is only either an InnerNode
or a Leaf
which I would normally implement like this:
class Node {
public:
virtual ~Node() = default;
};
class InnerNode: public Node {
std::vector<std::unique_ptr<Node>> children;
...
};
class Leaf: public Node {
...
};
Now I would like to have a template method for_each
but template methods cannot be virtual. To work around this I could implement for_each
like this:
class Node {
...
virtual InnerNode* get_inner_node() {
return nullptr;
}
virtual Leaf* get_leaf() {
return nullptr;
}
template <class F> void for_each(F&& f) {
if (InnerNode* inner_node = get_inner_node()) {
inner_node->for_each_inner_node(std::forward(f));
}
else if (Leaf* leaf = get_leaf()) {
leaf->for_each_leaf(std::forward(f));
}
}
};
class InnerNode: public Node {
...
InnerNode* get_inner_node() override {
return this;
}
template <class F> void for_each_inner_node(F&& f) {
...
}
};
class Leaf: public Node {
...
Leaf* get_leaf() override {
return this;
}
template <class F> void for_each_leaf(F&& f) {
...
}
};
Alternatively I could use dynamic_cast
or std::variant
or I could store the type inside Node
. In the worst-case my code for for_each
uses two virtual method calls and one non-virtual method call, but I wonder what the performance of the alternative approaches would be. Is there a name for this kind of idiom and is there a best practice for how to solve it?