Как личное упражнение, я хочу реализовать шаблон посетителя с помощью shared_ptr. Я знаком с ациклическим гостевым документом Роберта Мартина, но обнаруживаю навязчивый характер виртуального accept() и необходимое создание класса {X} Visitor для каждого класса {X}. Мне нравится класс boost :: static_visitor, поскольку он инкапсулирует всю логику локально без необходимости {X} :: accept() и {X} Visitor.C++ шаблон метапрограммирования для создания boost :: variant из shared_ptr и boost :: static_visitor
Что я ищу - это подсказка (как я уже сказал, я делаю это как упражнение) о том, как создать функцию функции шаблона 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;
}
Спасибо за ответ. См. Мой комментарий к решению UncleBen. То, с чем я играю, - это преобразование base_ptr в неназванное значение, единственная цель которого - действовать как дискриминатор функции variant_visitor :: operator(). Значение не используется; оператор() будет использовать base_ptr, прошедший его. –
themis
@themis: То, что вы ищете, - это способ ** downcast ** базовый указатель на подходящий тип указателя в варианте? Я добавил что-то с препроцессорной библиотекой, но у меня были бы большие сомнения в этом. Вероятно, он имеет довольно низкую производительность и может давать ложные результаты, если базовый тип должен быть указан до самого производного типа. – visitor