问题
I am trying to write a XML serializer and de-serializer for user defined classes. Please refer to the code posted in Coliru
The deserializer i am unable to get the type resolved from the adt_proxy to the value type in question. The error is the read_handle function. Can anyone tell me what I am missing here ?
static inline void read_handle(FusionVisitorConcept& visitor, S& s)
{
visitor.start_member(name_t::call());
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, boost::fusion::at<N>(s));
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::read_handle(visitor, s);
}
回答1:
Indeed the ADT proxies are ruining the party here. It's the Law of Leaky Abstractions.
In particular, you can't deserialize a boost::lazy_disable_if_c<false, boost::fusion::result_of::at<Bar, mpl_::int_<0> > >::type
. Now, if you replace
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, boost::fusion::at<N>(s));
with
current_t tmp;
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, tmp);
boost::fusion::at<N>(s) = tmp;
It works. There's a side-effect though: now current_t
needs to be default-constructible.
Here's the fully working sample
Live On Coliru
#include <typeinfo>
#include <string>
#include <iostream>
#include <sstream>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/intrinsic.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/adt.hpp>
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>
class Bar {
int integer_value;
public:
Bar(int i_val=0):integer_value(i_val) { }
int get_integer_value() const { return integer_value; }
void set_integer_value(int i_val) { integer_value = i_val; }
};
class Foo {
Bar bar_value;
public:
Foo(int i_val=0):bar_value(i_val) { }
Bar get_bar_value() const { return bar_value; }
void set_bar_value(const Bar b_val) { bar_value = b_val; }
};
BOOST_FUSION_ADAPT_ADT(Bar,
(int, int, obj.get_integer_value(), obj.set_integer_value(val)))
BOOST_FUSION_ADAPT_ADT(Foo,
(Bar, Bar, obj.get_bar_value(), obj.set_bar_value(val)))
#define MY_ADT_MEMBER_NAME(CLASSNAME, IDX, MEMBERNAME) \
namespace boost { namespace fusion { namespace extension { \
template <> struct struct_member_name<CLASSNAME, IDX> { typedef char const *type; static type call() { return #MEMBERNAME; } \
}; } } }
MY_ADT_MEMBER_NAME(Bar, 0, integer_value)
MY_ADT_MEMBER_NAME(Foo, 0, bar_value)
namespace visitor {
template <typename Flavour, typename T> struct VisitorApplication;
namespace detail
{
template <typename V, typename Enable = void>
struct is_vector : boost::mpl::false_ { };
template <typename T>
struct is_vector<std::vector<T>, void> : boost::mpl::true_ { };
namespace iteration
{
// Iteration over a sequence
template <typename FusionVisitorConcept, typename S, typename N>
struct members_impl
{
// Type of the current member
typedef typename boost::fusion::result_of::value_at<S, N>::type current_t;
typedef typename boost::mpl::next<N>::type next_t;
typedef boost::fusion::extension::struct_member_name<S, N::value> name_t;
static inline void handle(FusionVisitorConcept& visitor, const S& s)
{
visitor.start_member(name_t::call());
VisitorApplication<FusionVisitorConcept, current_t>::handle(visitor, boost::fusion::at<N>(s));
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::handle(visitor, s);
}
static inline void read_handle(FusionVisitorConcept& visitor, S& s)
{
visitor.start_member(name_t::call());
current_t tmp;
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, tmp);
boost::fusion::at<N>(s) = tmp;
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::read_handle(visitor, s);
}
};
// End condition of sequence iteration
template <typename FusionVisitorConcept, typename S>
struct members_impl<FusionVisitorConcept, S, typename boost::fusion::result_of::size<S>::type>
{
static inline void handle(FusionVisitorConcept const&, const S&) { /*Nothing to do*/ }
static inline void read_handle(FusionVisitorConcept const&, S&) { /*Nothing to do*/ }
};
// Iterate over struct/sequence. Base template
template <typename FusionVisitorConcept, typename S>
struct Struct : members_impl<FusionVisitorConcept, S, boost::mpl::int_<0>> {};
} // iteration
template <typename FusionVisitorConcept, typename T>
struct array_application
{
typedef array_application<FusionVisitorConcept, T> type;
typedef typename T::value_type value_type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_array();
for (auto& el : t)
VisitorApplication<FusionVisitorConcept, value_type>::handle(visitor, el);
}
static inline void read_handle(FusionVisitorConcept& visitor, T& t)
{
visitor.empty_array();
for (auto& el : t)
VisitorApplication<FusionVisitorConcept, value_type>::read_handle(visitor, el);
}
};
template <typename FusionVisitorConcept, typename T>
struct struct_application
{
typedef struct_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_object();
iteration::Struct<FusionVisitorConcept, T>::handle(visitor, t);
}
static inline void read_handle(FusionVisitorConcept& visitor, T& t)
{
iteration::Struct<FusionVisitorConcept, T>::read_handle(visitor, t);
}
};
template <typename FusionVisitorConcept, typename T, typename Enable = void>
struct value_application
{
typedef value_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t) {
visitor.value(t);
}
static inline void read_handle(FusionVisitorConcept& visitor, T& t) {
visitor.value(t);
}
};
template <typename FusionVisitorConcept, typename T>
struct value_application<FusionVisitorConcept, boost::optional<T> >
{
typedef value_application<FusionVisitorConcept, boost::optional<T> > type;
static inline void handle(FusionVisitorConcept& visitor, const boost::optional<T>& t) {
if (t)
VisitorApplication<FusionVisitorConcept, T>::handle(visitor, *t);
else
; // perhaps some default action?
}
static inline void read_handle(FusionVisitorConcept& visitor, boost::optional<T>& t) {
if (t)
VisitorApplication<FusionVisitorConcept, T>::read_handle(visitor, *t);
else
; // perhaps some default action?
}
};
template <typename FusionVisitorConcept, typename T>
struct select_application
{
typedef
//typename boost::mpl::eval_if<boost::is_array<T>, boost::mpl::identity<array_application<FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<detail::is_vector<T>, boost::mpl::identity<array_application <FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<boost::fusion::traits::is_sequence<T>, boost::mpl::identity<struct_application<FusionVisitorConcept, T>>,
boost::mpl::identity<value_application<FusionVisitorConcept, T>>
> >::type type;
};
} // detail
template <typename FusionVisitorConcept, typename T>
struct VisitorApplication : public detail::select_application<FusionVisitorConcept, T>::type
{
};
}
template <typename FusionVisitorConcept, typename T>
void apply_fusion_visitor(FusionVisitorConcept& visitor, T const& o)
{
visitor::VisitorApplication<FusionVisitorConcept, T>::handle(visitor, o);
}
template <typename FusionVisitorConcept, typename T>
void apply_read_fusion_visitor(FusionVisitorConcept& visitor, T & o)
{
visitor::VisitorApplication<FusionVisitorConcept, T>::read_handle(visitor, o);
}
struct DisplayMemberVisitor {
typedef std::string result_type;
DisplayMemberVisitor() { ss << std::boolalpha; }
std::string complete() { return ss.str(); }
void start_member (const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
ss << "<" << name << ">";
}
void finish_member(const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
ss << "</" << name << ">";
}
template <typename T> void value(T const& value) {
std::cerr << __PRETTY_FUNCTION__ << ":\t" << value << "\n";
ss << value;
}
//template <typename T> void value(boost::optional<T>& value);
void empty_object() { std::cerr << __PRETTY_FUNCTION__ << "\n"; }
void empty_array() { std::cerr << __PRETTY_FUNCTION__ << "\n"; }
private:
std::stringstream ss;
};
struct ReadMemberVisitor {
typedef std::string result_type;
ReadMemberVisitor(std::string ss_) { ss = ss_; }
void start_member (const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
std::string tag = "<" + std::string(name) + ">";
ss = ss.substr(tag.length(),ss.length());
}
void finish_member(const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
std::string tag = "</" + std::string(name) + ">";
ss = ss.substr(tag.length(),ss.length());
}
template <typename T> void value(T &value) {
auto pos = ss.find('<');
std::string value_string = ss.substr(0,pos);
std::cerr << __PRETTY_FUNCTION__ << " -> '" << value_string << "'\n";
value = boost::lexical_cast<T>(value_string);
ss = ss.substr(pos,ss.length());
}
private:
std::string ss;
};
int main()
{
// Bar
{
Bar b(8);
DisplayMemberVisitor vis;
apply_fusion_visitor(vis, b);
std::cout << "\n" << vis.complete() << "\n";
Bar cloned;
ReadMemberVisitor rv(vis.complete());
apply_read_fusion_visitor(rv, cloned);
}
std::cout << "\n-----------\n";
// Foo
Foo const f{78};
std::string f_serialized;
{
DisplayMemberVisitor vis;
apply_fusion_visitor(vis, f);
f_serialized = vis.complete();
std::cout << "\n" << f_serialized << "\n";
}
std::cout << "\n-----------\n";
Foo cloned{0};
ReadMemberVisitor rv(f_serialized);
apply_read_fusion_visitor(rv, cloned);
std::cout << "\n-----------\n";
std::cout << f.get_bar_value().get_integer_value() << " == " << cloned.get_bar_value().get_integer_value() << "\n";
}
Output:
void DisplayMemberVisitor::empty_object()
void DisplayMemberVisitor::start_member(const char*): 'integer_value'
void DisplayMemberVisitor::value(const T&) [with T = int]: 8
void DisplayMemberVisitor::finish_member(const char*): 'integer_value'
<integer_value>8</integer_value>
void ReadMemberVisitor::start_member(const char*): 'integer_value'
void ReadMemberVisitor::value(T&) [with T = int] -> '8'
void ReadMemberVisitor::finish_member(const char*): 'integer_value'
-----------
void DisplayMemberVisitor::empty_object()
void DisplayMemberVisitor::start_member(const char*): 'bar_value'
void DisplayMemberVisitor::empty_object()
void DisplayMemberVisitor::start_member(const char*): 'integer_value'
void DisplayMemberVisitor::value(const T&) [with T = int]: 78
void DisplayMemberVisitor::finish_member(const char*): 'integer_value'
void DisplayMemberVisitor::finish_member(const char*): 'bar_value'
<bar_value><integer_value>78</integer_value></bar_value>
-----------
void ReadMemberVisitor::start_member(const char*): 'bar_value'
void ReadMemberVisitor::start_member(const char*): 'integer_value'
void ReadMemberVisitor::value(T&) [with T = int] -> '78'
void ReadMemberVisitor::finish_member(const char*): 'integer_value'
void ReadMemberVisitor::finish_member(const char*): 'bar_value'
-----------
78 == 78
来源:https://stackoverflow.com/questions/26885379/boost-fusion-error-in-substituting-the-adt-proxy-type-to-the-value-type