6

A

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

我想fusion::map从结构中生成 a ,使其包含fusion::pairs: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 被用作关联序列,但我还没有找到一种方法来从中构建映射。特别是,如果我迭代它,我只会得到值。如果我可以遍历真正有用的键,因为那样我可以压缩值和键来构建地图,但我还没有找到一种方法来做到这一点。

4

2 回答 2

3

您应该使用Associative Iterator接口 - 它提供result_of::key_of<I>::type元功能。

我在旧记录中找到了代码,并提取了相关部分。我在实现SoA 向量期间使用了它(正如我从聊天中了解到的 - 你也在实现它),但最终切换到了fusion::map. 我想我这样做是为了获得正常结构和引用结构的统一接口(即两者都通过类型标签访问)。

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>();
}
于 2013-10-29T13:57:01.660 回答
2

我记得在过去的某个地方看到过这个。

我发现了一篇知道缺少链接的博客文章: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

完整的节目清单

整合一切,在 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";
}
于 2013-10-29T12:34:01.207 回答