作为个人练习,我想使用shared_ptr实现访问者模式。我熟悉罗伯特·马丁的非循环访问者论文,但发现虚拟accept()的侵入性,并且必须为每个{X}类创建一个{X}访问者类令人不快。我喜欢boost :: static_visitor类,因为它在本地封装了所有逻辑,而不需要{X} :: accept()和{X} 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;
}
答案 0 :(得分:2)
我可能误解了这个问题,但是如果你想对包含共享指针而不是普通指针的变量使用相同的variant_visitor
,也许这可以通过另一个从{{获得指针的访问者来实现1}}并将其传递给另一位访客。
shared_ptr
编辑:您似乎正在构想的下载者。
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
struct Base {};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef boost::shared_ptr<Base> base_ptr;
typedef boost::variant<boost::shared_ptr<A>,boost::shared_ptr<B>,boost::shared_ptr<C> > base_variant;
template <class Visitor>
struct visit_shared_ptr_get: public boost::static_visitor<typename Visitor::result_type>
{
//for unary visitors
template <class FirstArg>
typename Visitor::result_type operator()(FirstArg& first) const
{
return Visitor()(first.get());
}
//for binary visitors, only the first argument is "ripped"
template <class FirstArg, class SecondArg>
typename Visitor::result_type operator()(FirstArg& first, SecondArg& second) const
{
return Visitor()(first.get(), second);
}
};
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(boost::shared_ptr<A>(new A()));
boost::apply_visitor(boost::bind(visit_shared_ptr_get<variant_visitor>(), _1, b), v);
return EXIT_SUCCESS;
}
答案 1 :(得分:0)
您不能将访问者用于类型推导,因为它只有一个模板参数 - 用于result_type
。对于任意operator()
可能存储的所有类型,可以调用或不调用boost::variant
。
我只是猜测以下可能是您正在寻找的东西(我第一次使用boost的预处理器库):
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/preprocessor/repetition.hpp>
#define SHARED_PTR_TO_PTR(z, n, text) BOOST_PP_COMMA_IF(n) typename shared_ptr_to_ptr<text ## n>::type
template <class T>
struct shared_ptr_to_ptr { typedef T type; };
template <class T>
struct shared_ptr_to_ptr<std::shared_ptr<T> > {typedef T* type; };
template <class T>
struct unsmartify_variant;
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct unsmartify_variant<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T) > >
{
typedef boost::variant<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES, SHARED_PTR_TO_PTR, T)> type;
};
template <class Variant>
struct get_visitor: boost::static_visitor<typename unsmartify_variant<Variant>::type >
{
template <class SharedPtr>
typename unsmartify_variant<Variant>::type operator()(SharedPtr& p) const
{
return p.get();
}
};
template <class Variant>
typename unsmartify_variant<Variant>::type rip(Variant& variant)
{
return boost::apply_visitor(get_visitor<Variant>(), variant);
}
struct Base {};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef std::shared_ptr<Base> base_ptr;
typedef boost::variant<std::shared_ptr<A>,std::shared_ptr<B>,std::shared_ptr<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(std::shared_ptr<A>(new A()));
unsmartify_variant<base_variant>::type k = rip(v);
boost::apply_visitor(boost::bind(variant_visitor(), _1, b), k);
return EXIT_SUCCESS;
}
最大的问题是boost::variant
需要固定数量的参数。
同样看来variant
被非const引用传递给apply_visitor
,这意味着rip
的结果必须存储在命名变量中。