Метапрограммирование шаблона C ++ для создания boost :: variant из shared_ptr и boost :: static_visitor

В качестве личного упражнения я хочу реализовать шаблон посетителя с помощью shared_ptr. Я знаком с ациклической статьей Роберта Мартина о посетителях, но считаю навязчивый характер виртуального accept () и необходимое создание класса посетителя {X} для каждого класса {X} неприятным. Мне нравится класс boost :: static_visitor, поскольку он инкапсулирует всю логику локально без необходимости использования {X} :: accept () и {X} Visitor.

Я ищу подсказку (как я уже сказал, я Я делаю это в качестве упражнения) о том, как создать функцию шаблона function rip , о которой я упоминаю ниже. Я думаю, он должен иметь форму:

template <typename U, typename T1, typename T2, ...>
boost::variant<T1, T2, ...> rip(U& p, boost::static_visitor<T1, T2, ...> sv)
{
    if (T1 t1 = dynamic_cast<T1>(p)) return boost::variant<T1, ...>(t1);
    ... and so on, splitting static_visitor
    return 0;  // or throw an exception
}

Любые подсказки или указатели на обучающие программы, делающие подобные вещи, будут оценены. Спасибо.

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <boost/bind.hpp>
#include <boost/variant.hpp>


struct Base {};
struct A : Base {};
struct B : Base {};
struct C : Base {};

typedef std::shared_ptr<Base> base_ptr;
typedef boost::variant<A*,B*,C*> base_variant;
struct variant_visitor : public boost::static_visitor<void> {
    void operator()(A*, base_ptr) const {std::cout << "A*\n";}
    void operator()(B*, base_ptr) const {std::cout << "B*\n";}
    void operator()(C*, base_ptr) const {std::cout << "C*\n";}
};


int main(int, char**)
{
    // This works, of course.
    base_ptr b(new A());
    base_variant v(new A());
    boost::apply_visitor(boost::bind(variant_visitor(), _1, b), v);

    // How could we use a shared_ptr with a variant?  I almost see
    // the template magic, a function to iterate over the template
    // types from the variant_visitor and return an "any<...>".
    // base_variant rip(base_ptr&, variant_visitor) {...}
    // boost::apply_visitor(boost::bind(variant_visitor(), _1, b), rip(b, variant_visitor()));

    return EXIT_SUCCESS;
}
1
задан GManNickG 9 September 2010 в 04:11
поделиться