Boost fusion sequence type and name identification for structs and class

前端 未结 2 830
無奈伤痛
無奈伤痛 2021-01-05 23:14

I am trying to use boost fusion for one of my projects and I an figuring out how to get type names and variable names for structures and classes.

#include &         


        
2条回答
  •  既然无缘
    2021-01-05 23:50

    There's boost::fusion::extension::struct_member_name to access the names.

    Here's a generic fusion object visitor that I use:

    namespace visitor {
    
        template  struct VisitorApplication;
    
        namespace detail
        {
            template 
            struct is_vector : boost::mpl::false_ { };
    
            template 
            struct is_vector, void> : boost::mpl::true_ { };
    
            namespace iteration
            {
                // Iteration over a sequence
                template 
                    struct members_impl
                    {
                        // Type of the current member
                        typedef typename boost::fusion::result_of::value_at::type   current_t;
                        typedef typename boost::mpl::next::type                        next_t;
                        typedef boost::fusion::extension::struct_member_name name_t;
    
                        static inline void handle(FusionVisitorConcept& visitor, const S& s)
                        {
                            visitor.start_member(name_t::call());
                            VisitorApplication::handle(visitor, boost::fusion::at(s));
                            visitor.finish_member(name_t::call());
                            members_impl::handle(visitor, s);
                        }
                    };
    
                // End condition of sequence iteration
                template 
                    struct members_impl::type>
                    {
                        static inline void handle(FusionVisitorConcept const&, const S&) { /*Nothing to do*/ }
                    };
    
                // Iterate over struct/sequence. Base template
                template 
                    struct Struct : members_impl> {};
    
        } // iteration
    
        template 
            struct array_application
            {
                typedef array_application 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::handle(visitor, el);
                }
            };
    
        template 
            struct struct_application
            {
                typedef struct_application type;
    
                static inline void handle(FusionVisitorConcept& visitor, const T& t)
                {
                    visitor.empty_object();
                    iteration::Struct::handle(visitor, t);
                }
            };
    
        template 
            struct value_application
            {
                typedef value_application type;
    
                static inline void handle(FusionVisitorConcept& visitor, const T& t) {
                    visitor.value(t);
                }
            };
    
        template 
            struct value_application >
            {
                typedef value_application > type;
    
                static inline void handle(FusionVisitorConcept& visitor, const boost::optional& t) {
                    if (t)
                        VisitorApplication::handle(visitor, *t);
                    else
                        ; // perhaps some default action?
                }
            };
    
        template 
            struct select_application
            {
                typedef
                    //typename boost::mpl::eval_if,                  boost::mpl::identity>,
                    typename boost::mpl::eval_if,                  boost::mpl::identity>,
                    typename boost::mpl::eval_if, boost::mpl::identity>,
                    boost::mpl::identity>
                    > >::type type;
            };
    
        } // detail
    
        template 
            struct VisitorApplication : public detail::select_application::type
        {
        };
    }
    
    template 
    void apply_fusion_visitor(FusionVisitorConcept& visitor, T const& o)
    {
        visitor::VisitorApplication::handle(visitor, o);
    }
    

    You can use it by supplying a visitor, e.g. for xml-like output:

    struct DisplayMemberVisitor {
        typedef std::string result_type;
    
        DisplayMemberVisitor() { ss << std::boolalpha; }
    
        std::string complete() { return ss.str(); }
    
        void start_member (const char* name) { 
            ss << "<" << name << ">";
        }
        void finish_member(const char* name) { 
            ss << "";
        }
    
        template  void value(T const& value) {
            ss << value;
        }
    
        void empty_object() { }
        void empty_array()  { }
    
    private:
        std::stringstream ss;
    };
    

    See it Live On Coliru where (including some debug output) it prints:

    33false34true

    Note that the ADT adaptation macro doesn't include a name (because none is available). You can probably quite easily make a macro FUSION_ADAPT_KEYD_ADT that also accepts a name and generates the relevant specializations of boost::fusion::extension::struct_member_name.

    BONUS MATERIAL

    Adding member name traits to ADT adapted members

    Here's a simplistic approach that shows what little amount of work needs to be done.

    #define MY_ADT_MEMBER_NAME(CLASSNAME, IDX, MEMBERNAME)                                                                                   \
            namespace boost { namespace fusion { namespace extension {                                                                       \
                template <> struct struct_member_name { typedef char const *type; static type call() { return #MEMBERNAME; } \
            }; } } }
    
    MY_ADT_MEMBER_NAME(Bar, 0, integer_value)
    MY_ADT_MEMBER_NAME(Bar, 1, boolean_value)
    

    This defines a macro to avoid most of the repetition. If you are a BOOST_PP whizkid you could somehow weave this into an adt_ex.hpp¹ header of sorts, so you could instead say:

    BOOST_FUSION_ADAPT_ADT(Bar, // NOTE THIS PSEUDO-CODE
        (integer_value, int,  int,  obj.get_integer_value(), obj.set_integer_value(val))
        (boolean_value, bool, bool, obj.get_boolean_value(), obj.set_boolean_value(val)))
    

    For now here's the ADT adapted trick Live On Coliru

    ¹ in case you're interested, here's a tarball of a prepared adt_ex tree (drop in alongsize adt.hpp): adt_ex.tgz as a starting point. It's just adt* but with macros and header guards renamed to adt_ex*

提交回复
热议问题