Boost融合序列类型和结构和类的名称标识 [英] Boost fusion sequence type and name identification for structs and class

查看:143
本文介绍了Boost融合序列类型和结构和类的名称标识的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图对我的一个项目使用boost融合,我想出了如何获得类型名称和结构和类的变量名称。

  #include< typeinfo> 
#include< string>
#include< iostream>
#include< boost / fusion / include / sequence.hpp>
#include< boost / fusion / include / algorithm.hpp>
#include< boost / fusion / include / vector.hpp>
#include< boost / fusion / include / adapt_struct.hpp>
#include< boost / fusion / include / adapt_adt.hpp>

#include< boost / lexical_cast.hpp>

使用命名空间boost :: fusion;

struct Foo
{
int integer_value;
bool boolean_value;
};


class Bar
{
int integer_value;
bool boolean_value;
public:
Bar(int i_val,bool b_val):integer_value(i_val),boolean_value(b_val){}
int get_integer_value()const {return integer_value; }
void set_integer_value(int i_val){integer_value = i_val; }
bool get_boolean_value()const {return boolean_value;} }
void set_boolean_value(bool b_val){boolean_value = b_val; }
};

BOOST_FUSION_ADAPT_STRUCT(
Foo,
(int,integer_value)
(bool,boolean_value)


BOOST_FUSION_ADAPT_ADT b $ b Bar,
(int,int,obj.get_integer_value(),obj.set_integer_value(val))
(bool,bool,obj.get_boolean_value(),obj.set_boolean_value b $ b)


struct DisplayMembers
{

template< typename T>
void operator()(T& t)const {
std :: cout< typeid(t).name()< :<< boost :: lexical_cast< std :: string>(t)<< std :: endl;
}

};

int main(int argc,char * argv [])
{
struct Foo f = {33,false};
for_each(f,DisplayMembers());

Bar b(34,true);
for_each(b,DisplayMembers());
return 0;
}

在上面的例子中,结果是
int:33
bool:0
struct boost :: fusion :: extension :: adt_attribute_proxy:34
struct boost :: fusion :: extension :: adt_attribute_proxy:1



我想要的结果为
int:integer_value:33
bool:boolean_value:0
int:integer_value:34
bool:boolean_value:1

解决方案

boost :: fusion :: extension :: struct_member_name< S,N :: value>

这是一个通用的融合对象访问者,我使用:

命名空间访问者{

模板< typename Flavor,typename T> struct VisitorApplication;

命名空间详细信息
{
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
{
//在序列上迭代
模板< typename FusionVisitorConcept,typename S,typename N>
struct members_impl
{
//当前成员的类型
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);
}
};

//序列迭代的结束条件
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 * /}
};

//迭代结构/序列。基本模板
模板< 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>类型;

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);
}
};

template< typename FusionVisitorConcept,typename T>
struct struct_application
{
typedef struct_application< FusionVisitorConcept,T>类型;

static inline void handle(FusionVisitorConcept& visitor,const T& t)
{
visitor.empty_object
iteration :: Struct< FusionVisitorConcept,T> :: handle(visitor,t);
}
};

template< typename FusionVisitorConcept,typename T,typename Enable = void>
struct value_application
{
typedef value_application< FusionVisitorConcept,T>类型;

static inline void handle(FusionVisitorConcept& visitor,const T& t){
visitor.value(t);
}
};

template< typename FusionVisitorConcept,typename T>
struct value_application< FusionVisitorConcept,boost :: optional< T> >
{
typedef value_application< FusionVisitorConcept,boost :: optional< T> >类型;

static inline void handle(FusionVisitorConcept& visitor,const boost :: optional< T>& t){
if(t)
VisitorApplication< FusionVisitorConcept,T& handle(visitor,* t);
else
; //或者一些默认动作?
}
};

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& 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);
}

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< < <<名称<< >;
}
void finish_member(const char * name){
ss<< < /<<名称<< >;
}

template< typename T> void value(T const& value){
ss<<值;
}

void empty_object(){}
void empty_array(){}

private:
std :: stringstream ss;
};

查看 Live on Coliru 其中(包括一些调试输出):


< integer_value> 33< / integer_value>< boolean_value> false< / boolean_value>< integer_value> 34< / integer_value>< boolean_value> true< / boolean_value>


请注意,ADT自适应宏不包含名称)。你可以很容易地创建一个宏 FUSION_ADAPT_KEYD_ADT ,它也接受一个名称并生成 boost :: fusion :: extension :: struct_member_name



奖金材料



将成员名称traits添加到ADT适配成员



这里是一个简单的方法,显示需要做少量的工作。

  #define MY_ADT_MEMBER_NAME(CLASSNAME,IDX,MEMBERNAME)\ 
namespace boost {namespace fusion {namespace extension { \\
模板<> struct struct_member_name< CLASSNAME,IDX> {typedef char const * type;静态类型call(){return #MEMBERNAME; } \
}; }}}

MY_ADT_MEMBER_NAME(Bar,0,integer_value)
MY_ADT_MEMBER_NAME(Bar,1,boolean_value)

这定义了一个宏,以避免大多数重复。如果您是BOOST_PP whizkid,您可以用某种方式将它编织成 adt_ex.hpp ¹标题,因此您可以改为:

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

现在这里是ADT的适应技巧 Live On Coliru



¹如果您有兴趣,下面是一个准备好的adt_ex树(drops insize adt.hpp)的tarball: adt_ex.tgz 作为起点。它只是adt *,但宏和标题卫士重命名为adt_ex *


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 <typeinfo>
    #include <string>
    #include <iostream>
    #include <boost/fusion/include/sequence.hpp>
    #include <boost/fusion/include/algorithm.hpp>
    #include <boost/fusion/include/vector.hpp>
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/adapt_adt.hpp>

    #include <boost/lexical_cast.hpp>

    using namespace boost::fusion;

    struct Foo
    {
        int integer_value;
        bool boolean_value;
    };


    class Bar
    {
        int integer_value;
        bool boolean_value;
    public:
        Bar(int i_val, bool b_val):integer_value(i_val),boolean_value(b_val) {}
        int     get_integer_value() const       { return integer_value; }
        void    set_integer_value(int i_val)    { integer_value = i_val; }
        bool    get_boolean_value() const       { return boolean_value; }
        void    set_boolean_value(bool b_val)   { boolean_value = b_val; }
    };

    BOOST_FUSION_ADAPT_STRUCT(
        Foo,
        (int, integer_value)
        (bool, boolean_value)    
    )

    BOOST_FUSION_ADAPT_ADT(
        Bar,
        (int, int, obj.get_integer_value() , obj.set_integer_value(val))
        (bool, bool, obj.get_boolean_value(), obj.set_boolean_value(val))    
    )


    struct DisplayMembers
    {

        template <typename T>
        void operator()(T& t) const {
            std::cout << typeid(t).name() << " : " << boost::lexical_cast<std::string>(t) << std::endl;
        }

    };

    int main(int argc, char *argv[]) 
    {
      struct Foo f = { 33, false};
      for_each(f, DisplayMembers());

      Bar b(34,true);
      for_each(b, DisplayMembers());
      return 0;
    }

In the above example the result is int : 33 bool : 0 struct boost::fusion::extension::adt_attribute_proxy : 34 struct boost::fusion::extension::adt_attribute_proxy : 1

I want the result as int : integer_value : 33 bool : boolean_value : 0 int : integer_value : 34 bool : boolean_value : 1

解决方案

There's boost::fusion::extension::struct_member_name<S, N::value> to access the names.

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

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);
                    }
                };

            // 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*/ }
                };

            // 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);
            }
        };

    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);
            }
        };

    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);
            }
        };

    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?
            }
        };

    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);
}

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 << "</" << name << ">";
    }

    template <typename T> 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:

<integer_value>33</integer_value><boolean_value>false</boolean_value><integer_value>34</integer_value><boolean_value>true</boolean_value>

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<CLASSNAME, IDX> { 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*

这篇关于Boost融合序列类型和结构和类的名称标识的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆