是否有可能从适应的结构生成融合图?

时间:2013-10-29 11:32:08

标签: c++ boost-fusion

A成为:

struct A {
  int a;
  std::string b;
  struct keys {
    struct a;
    struct b;
  };
};

我想从结构中生成fusion::map,使其包含fusion::pair s:fusion::pair<A::keys::a, int>fusion::pair<A::keys::b, std::string>。像

这样的东西
A a;
fusion::make_map<A>(a)

我尝试过BOOST_FUSION_ADAPT_ASSOC_STRUCT

BOOST_FUSION_ADAPT_ASSOC_STRUCT(
    A,
    (int,  a, A::keys::a)
    (std::string, b, A::keys::b)

这使A适合用作关联序列,但我还没有找到从中构造地图的方法。特别是,如果我迭代它,我只得到值。如果我可以迭代那些真正有用的键,因为那时我可以压缩值和键来构建一个地图,但我还没有找到办法做到这一点。

2 个答案:

答案 0 :(得分:3)

您应该使用Associative Iterator界面 - 它提供result_of::key_of<I>::type metafunciton。

我在旧记录中找到了代码,并提取了相关部分。 我在SoA vector的实现过程中使用过它(正如我从聊天中所理解的那样 - 你也在实现它),但最终只转换为fusion::map的明确定义。我认为我这样做是为了拥有正常结构和引用结构的统一接口(即两者都通过类型标签访问)。

Live Demo on Coliru

namespace demo
{
    struct employee
    {
        std::string name;
        int age;
    };
}

namespace keys
{
    struct name;
    struct age;
}

BOOST_FUSION_ADAPT_ASSOC_STRUCT
(
    demo::employee,
    (std::string, name, keys::name)
    (int, age, keys::age)
)

template<typename> void type_is();

int main()
{
    type_is<as_fusion_map<demo::employee>::type>();
}

结果是:

main.cpp:(.text.startup+0x5): undefined reference to `void type_is<

boost::fusion::map
<
    boost::fusion::pair<keys::name, std::string>,
    boost::fusion::pair<keys::age, int>,
    boost::fusion::void_,
    boost::fusion::void_,
    boost::fusion::void_,
    boost::fusion::void_,
    boost::fusion::void_,
    boost::fusion::void_,
    boost::fusion::void_,
    boost::fusion::void_
>

>()'

这是完整的实施

//             Copyright Evgeny Panasyuk 2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)


// Reduced from larger case, some includes may not be needed

#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/sequence/intrinsic/value_at_key.hpp>
#include <boost/fusion/include/adapt_assoc_struct.hpp>
#include <boost/fusion/sequence/intrinsic/at_key.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/view/zip_view.hpp>
#include <boost/fusion/container/map.hpp>
#include <boost/fusion/algorithm.hpp>

#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>

#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

#include <iostream>
#include <iterator>
#include <ostream>
#include <string>

#include <boost/mpl/push_front.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/iterator.hpp>
#include <boost/fusion/iterator/next.hpp>
#include <boost/fusion/iterator/equal_to.hpp>
#include <boost/fusion/iterator/key_of.hpp>
#include <boost/fusion/iterator/value_of.hpp>

using namespace boost;
using namespace std;

using fusion::at_key;
using fusion::at_c;

// ____________________________________________________________________________________ //

namespace res_of=boost::fusion::result_of;
using namespace boost::fusion;

template<typename Vector,typename First,typename Last,typename do_continue>
struct to_fusion_map_iter;

template<typename Vector,typename First,typename Last>
struct to_fusion_map_iter<Vector,First,Last,mpl::false_>
{
    typedef typename res_of::next<First>::type Next;
    typedef typename mpl::push_front
    <
        typename to_fusion_map_iter
        <
            Vector,
            Next,
            Last,
            typename res_of::equal_to<Next,Last>::type
        >::type,
        fusion::pair
        <
            typename res_of::key_of<First>::type,
            typename res_of::value_of_data<First>::type
        >
    >::type type;
};
template<typename Vector,typename First,typename Last>
struct to_fusion_map_iter<Vector,First,Last,mpl::true_>
{
    typedef Vector type;
};

template<typename FusionAssociativeSequence>
struct as_fusion_map
{
    typedef typename res_of::begin<FusionAssociativeSequence>::type First;
    typedef typename res_of::end<FusionAssociativeSequence>::type Last;
    typedef typename res_of::as_map
    <
        typename to_fusion_map_iter
        <
            mpl::vector<>,
            First,
            Last,
            typename res_of::equal_to<First,Last>::type
        >::type
    >::type type;
};

// ____________________________________________________________________________________ //

// Defenition of structure:

namespace demo
{
    struct employee
    {
        std::string name;
        int age;
    };
}

namespace keys
{
    struct name;
    struct age;
}

BOOST_FUSION_ADAPT_ASSOC_STRUCT
(
    demo::employee,
    (std::string, name, keys::name)
    (int, age, keys::age)
)

// ____________________________________________________________________________________ //
template<typename> void type_is();

int main()
{
    type_is<as_fusion_map<demo::employee>::type>();
}

答案 1 :(得分:2)

我记得曾经在某个地方见过这个。

我找到了blog post知道缺失的链接:boost::fusion::extension::struct_member_name

我已经改编了该博文的代码。我仍然不认为代码是干净的,并且有强烈的感觉,这可以更优雅地完成。但是,现在你可以这样做:

struct A {
  int a;
  typedef std::string strings[5];
  strings b;
};

BOOST_FUSION_ADAPT_STRUCT(A, (int, a)(A::strings, b))

int main() {
    using FusionDumping::dump;
    A f = { 42, { "The End Of The Universe", "Thanks For All The Fish", "Fwoop fwoop fwoop", "Don't Panic" } };
    std::cout << dump(f) << "\n";
}

打印:

STRUCT A
field a int: 42
field b ARRAY [
std::string: The End Of The Universe
std::string: Thanks For All The Fish
std::string: Fwoop fwoop fwoop
std::string: Don't Panic
std::string: 
]
ENDSTRUCT

FusionDumping是在这里实现业务结束的命名空间。除dump(std::ostream&, T const&)函数之外的所有内容都是实现细节:

namespace FusionDumping 
{
    // everything except the `dump(std::ostream&, T const&)` function is an implementation detail
    using mangling::nameofType;

    template <typename T2> struct Dec_s;

    template <typename S, typename N> struct DecImplSeqItr_s {
        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 std::ostream& decode(std::ostream& os, S const& s) {
            os << "field " << name_t::call() << " ";
            Dec_s<current_t>::decode(os, boost::fusion::at<N>(s));
            return DecImplSeqItr_s<S, next_t>::decode(os, s);
        }
    };

    template <typename S>
    struct DecImplSeqItr_s<S, typename boost::fusion::result_of::size<S>::type > {
        static inline std::ostream& decode(std::ostream& os, S const& s) { return os; }
    };

    template <typename S>
    struct DecImplSeqStart_s:DecImplSeqItr_s<S, boost::mpl::int_<0> > {};

    template <typename S> struct DecImplSeq_s {
    typedef DecImplSeq_s<S> type;
    static std::ostream& decode(std::ostream& os, S const& s) {
        os << "STRUCT " << nameofType(s) << "\n";
        DecImplSeqStart_s<S>::decode(os, s);
        return os << "ENDSTRUCT\n";
    };
    };

    template <typename T2> struct DecImplArray_s {
    typedef DecImplArray_s<T2> type;
    typedef typename boost::remove_bounds<T2>::type slice_t;
    static const size_t size = sizeof(T2) / sizeof(slice_t);
    static inline std::ostream& decode(std::ostream& os, T2 const& t) {
        os << "ARRAY [\n";
        for(size_t idx=0; idx<size; idx++) { Dec_s<slice_t>::decode(os, t[idx]); }
        return os << "]\n";
    }
    };

    template <typename T2> struct DecImplVoid_s {
    typedef DecImplVoid_s<T2> type;
    static std::ostream& decode(std::ostream& os, T2 const& t) { 
        return os << nameofType(t) << ": " << t << "\n";
    };
    };

    template <typename T2> struct DecCalc_s {
    typedef 
        typename boost::mpl::eval_if< traits::is_sequence<T2>, DecImplSeq_s<T2>, 
        typename boost::mpl::eval_if< boost::is_array<T2>, 
                                    boost::mpl::identity< DecImplArray_s<T2> >,
        DecImplVoid_s<T2>   > >
    ::type type;
    };

    template <typename T2> struct Dec_s : public DecCalc_s<T2>::type { };

    template <typename Data>
    struct Dumper
    {
        Dumper(Data const& data) : data(data) {}
        friend std::ostream& operator<<(std::ostream& os, const Dumper& manip) {
            return Dec_s<Data>::decode(os, manip.data);
        }
    private:
        Data const& data;
    };

    template <typename Data>
        Dumper<Data> dump(Data const& data) { return { data }; }
}

正如您所看到的,还有一个松散的结尾,与打印类型名称相关(名称修改和typeid(T).name()是实现定义的)。这是一个适用于GCC / Clang的股票实施:

#ifdef DEMANGLING
#   include <cxxabi.h>
#   include <stdlib.h>

    namespace mangling {
        template <typename T> std::string nameofType(const T& v) {
            int     status;
            char   *realname = abi::__cxa_demangle(typeid(v).name(), 0, 0, &status);
            std::string name(realname? realname : "????");
            free(realname);

            return name;
        }
    }
#else
    namespace mangling {
        template <typename T> std::string nameofType(const T& v) {
            return std::string("typeid(") + typeid(v).name() + ")";
        }
    }
#endif

完整计划列表

整合所有内容,请参阅 Live On Coliru

供将来参考

#include <typeinfo>
#include <string>
#include <iostream>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/type_traits.hpp> // is_array, is_class, remove_bounds

#define DEMANGLING

#ifdef DEMANGLING
#   include <cxxabi.h>
#   include <stdlib.h>

    namespace mangling {
        template <typename T> std::string nameofType(const T& v) {
            int     status;
            char   *realname = abi::__cxa_demangle(typeid(v).name(), 0, 0, &status);
            std::string name(realname? realname : "????");
            free(realname);

            return name;
        }
    }
#else
    namespace mangling {
        template <typename T> std::string nameofType(const T& v) {
            return std::string("typeid(") + typeid(v).name() + ")";
        }
    }
#endif

namespace FusionDumping 
{
    // everything except the `dump(std::ostream&, T const&)` function is an implementation detail
    using mangling::nameofType;

    template <typename T2> struct Dec_s;

    template <typename S, typename N> struct DecImplSeqItr_s {
        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 std::ostream& decode(std::ostream& os, S const& s) {
            os << "field " << name_t::call() << " ";
            Dec_s<current_t>::decode(os, boost::fusion::at<N>(s));
            return DecImplSeqItr_s<S, next_t>::decode(os, s);
        }
    };

    template <typename S>
    struct DecImplSeqItr_s<S, typename boost::fusion::result_of::size<S>::type > {
        static inline std::ostream& decode(std::ostream& os, S const& s) { return os; }
    };

    template <typename S>
    struct DecImplSeqStart_s:DecImplSeqItr_s<S, boost::mpl::int_<0> > {};

    template <typename S> struct DecImplSeq_s {
    typedef DecImplSeq_s<S> type;
    static std::ostream& decode(std::ostream& os, S const& s) {
        os << "STRUCT " << nameofType(s) << "\n";
        DecImplSeqStart_s<S>::decode(os, s);
        return os << "ENDSTRUCT\n";
    };
    };

    template <typename T2> struct DecImplArray_s {
    typedef DecImplArray_s<T2> type;
    typedef typename boost::remove_bounds<T2>::type slice_t;
    static const size_t size = sizeof(T2) / sizeof(slice_t);
    static inline std::ostream& decode(std::ostream& os, T2 const& t) {
        os << "ARRAY [\n";
        for(size_t idx=0; idx<size; idx++) { Dec_s<slice_t>::decode(os, t[idx]); }
        return os << "]\n";
    }
    };

    template <typename T2> struct DecImplVoid_s {
    typedef DecImplVoid_s<T2> type;
    static std::ostream& decode(std::ostream& os, T2 const& t) { 
        return os << nameofType(t) << ": " << t << "\n";
    };
    };

    template <typename T2> struct DecCalc_s {
    typedef 
        typename boost::mpl::eval_if<boost::fusion::traits::is_sequence<T2>, DecImplSeq_s<T2>, 
        typename boost::mpl::eval_if< boost::is_array<T2>, 
                                    boost::mpl::identity< DecImplArray_s<T2> >,
        DecImplVoid_s<T2>   > >
    ::type type;
    };

    template <typename T2> struct Dec_s : public DecCalc_s<T2>::type { };

    template <typename Data>
    struct Dumper
    {
        Dumper(Data const& data) : data(data) {}
        friend std::ostream& operator<<(std::ostream& os, const Dumper& manip) {
            return Dec_s<Data>::decode(os, manip.data);
        }
    private:
        Data const& data;
    };

    template <typename Data>
        Dumper<Data> dump(Data const& data) { return { data }; }
}

struct A {
  int a;
  typedef std::string strings[5];
  strings b;
};

BOOST_FUSION_ADAPT_STRUCT(A, (int, a)(A::strings, b))

int main() {
    using FusionDumping::dump;
    A f = { 42, { "The End Of The Universe", "Thanks For All The Fish", "Fwoop fwoop fwoop", "Don't Panic" } };
    std::cout << dump(f) << "\n";
}