Ответ 1
Это, безусловно, можно улучшить (например, использовать интеллектуальные указатели для владения хвостом), но основная идея:
template <typename T>
struct cons_list {
T head;
cons_list<T>* tail;
explicit cons_list(T head, cons_list *tail = nullptr)
: head(head), tail(tail) {}
template <template<typename> class Visitor>
typename Visitor<T>::return_type accept(const Visitor<T>& visitor) {
return visitor.visit(head, tail);
}
};
template <typename T>
struct some_visitor {
typedef void return_type;
return_type visit(T head, cons_list<T>* tail) const {
std::cout << head << '\n';
if (tail != nullptr) tail->accept(*this);
}
};
Демо. Нет необходимости в виртуальной диспетчеризации и иерархиях классов. nullptr
- это С++ 11, но он должен работать нормально на 03.
Возможно, было бы лучше реализовать accept
как бесплатную функцию, а не использовать нулевые указатели как nil node, но, как я уже сказал, это основная вещь.
Примечание: это более или менее идея boost:: static_visitor.
Полная версия С++ 11 Boost.Variant(требует псевдонимов шаблонов). Не проверено, потому что у меня нет g++ 4.7 рядом.
struct nil_node {};
template <typename T> cons_node;
template <typename T>
using cons_list = boost::make_recursive_variant<
nil_node, cons_node<T>
>::type;
template <typename T>
struct cons_node {
T head;
cons_list<T> tail;
explicit cons_node(T head, const cons_list<T>& tail)
: head(head), tail(tail)
{}
};
template <typename T>
struct some_visitor : boost::static_visitor<T> {
void operator()(nil_node&) {}
void operator()(cons_node<T>& node) {
std::cout << node.head << '\n';
boost::apply_visitor(node.tail, *this);
}
};
int main() {
cons_node<int> x(1, cons_node<int>(2, cons_node<int>(3, nil_node())));
boost::apply_visitor(some_visitor<int>(), x);
};