让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适合用作关联序列,但我还没有找到从中构造地图的方法。特别是,如果我迭代它,我只得到值。如果我可以迭代那些真正有用的键,因为那时我可以压缩值和键来构建一个地图,但我还没有找到办法做到这一点。
答案 0 :(得分:3)
您应该使用Associative Iterator
界面 - 它提供result_of::key_of<I>::type
metafunciton。
我在旧记录中找到了代码,并提取了相关部分。
我在SoA vector的实现过程中使用过它(正如我从聊天中所理解的那样 - 你也在实现它),但最终只转换为fusion::map
的明确定义。我认为我这样做是为了拥有正常结构和引用结构的统一接口(即两者都通过类型标签访问)。
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";
}