zrb*_*zrb 0 c++ metaprogramming boost-fusion
我正在尝试Fusion并发现了一些非常奇怪的东西......这是代码......我用// ############来突出显示有问题的代码.在这里麻烦######
#include <tr1/cstdint>
#include <tr1/functional>
#include <string>
#include <iostream>
// #define FUSION_MAX_VECTOR_SIZE 64
#define BOOST_MPL_LIMIT_STRING_SIZE 128
#include <boost/type_traits.hpp>
#include <boost/mpl/string.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/tuple.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/container/generation.hpp>
#include <boost/fusion/container/generation/vector_tie.hpp>
typedef std::tr1::int32_t int32;
typedef std::tr1::int64_t int64;
template < class type_const_ref >
struct remove_const_reference
{
typedef typename boost::remove_reference < type_const_ref >::type type_const;
typedef typename boost::remove_const < type_const >::type type;
};
template < class T >
class MetaClass;
namespace fusion = boost::fusion;
template < class T >
struct ConstRefFieldMap
{
typedef typename MetaClass < T >::FieldNames FieldNames;
typedef typename MetaClass < T >::ConstRefFields ConstRefFields;
typedef typename boost::fusion::result_of::zip < FieldNames const, ConstRefFields const >::type type;
};
template < class T >
static typename MetaClass < T >::FieldNames fieldNames()
{
return typename MetaClass < T >::FieldNames();
}
template < class T >
static typename MetaClass < T >::ConstRefFields constRefFields(T const &obj)
{
return MetaClass < T >::constRefFields(obj);
}
template < class T >
static typename ConstRefFieldMap < T >::type const constRefFieldMap(T const &obj)
{
return boost::fusion::zip(fieldNames < T >(), constRefFields(obj));
}
class Currency
{
private:
typedef MetaClass < Currency > Meta;
friend class MetaClass < Currency >;
private:
std::string m_isoCode;
int32 m_rank;
public:
Currency(std::string const &isoCode, int32 const rank)
: m_isoCode(isoCode)
, m_rank(rank)
{
}
std::string const& getIsoCode() const
{
return m_isoCode;
}
int32 const getRank() const
{
return m_rank;
}
private:
void setIsoCode(std::string const &isoCode)
{
m_isoCode = isoCode;
}
public:
void setRank(int32 rank)
{
m_rank = rank;
}
};
template <>
class MetaClass < Currency >
{
public:
typedef Currency data_type;
public:
typedef std::string IsoCodeType;
typedef int32 RankType;
typedef boost::fusion::vector <
boost::mpl::string < 'i', 's', 'o', 'C', 'o', 'd', 'e' >
, boost::mpl::string < 'r', 'a', 'n', 'k' >
> FieldNames;
typedef boost::fusion::vector <
IsoCodeType &
, RankType &
> MutableRefFields;
typedef boost::fusion::vector <
IsoCodeType const &
, RankType const &
> ConstRefFields;
static MutableRefFields mutableRefFields(Currency &obj)
{
return MutableRefFields(obj.m_isoCode, obj.m_rank);
}
static ConstRefFields constRefFields(Currency const &obj)
{
return ConstRefFields(obj.m_isoCode, obj.m_rank);
}
};
template < class T, class U >
static typename ConstRefFieldMap < T >::type const constRefFieldMapTest(T const &obj, U const &u)
{
return boost::fusion::zip(fieldNames < T >(), u);
}
int main()
{
Currency const EUR("EUR", 500);
using boost::fusion::any;
{
std::cout << boost::fusion::at_c < 0 >(constRefFields(EUR)) << " : " << boost::fusion::at_c < 1 >(constRefFields(EUR)) << std::endl;
ConstRefFieldMap < Currency >::type const &fm = boost::fusion::zip(fieldNames < Currency >(), constRefFields(EUR));
// ############ TROUBLE HERE ######
// ConstRefFieldMap < Currency >::type const &fm = constRefFieldMap(EUR);
// ############ TROUBLE HERE ######
{
{
typedef boost::fusion::result_of::at_c < ConstRefFieldMap < Currency >::type, 0 >::type field_value_type;
field_value_type const v = boost::fusion::at_c < 0 >(fm);
typedef boost::fusion::result_of::at_c < field_value_type, 0 >::type field_name_type;
field_name_type const n = boost::fusion::at_c < 0 >(v);
typedef boost::fusion::result_of::at_c < field_value_type, 1 >::type field_data_type;
field_data_type const d = boost::fusion::at_c < 1 >(v);
std::cout << boost::mpl::c_str < remove_const_reference < field_name_type >::type >::value << " : " << d << std::endl;
}
{
typedef boost::fusion::result_of::at_c < ConstRefFieldMap < Currency >::type, 1 >::type field_value_type;
field_value_type const v = boost::fusion::at_c < 1 >(fm);
typedef boost::fusion::result_of::at_c < field_value_type, 0 >::type field_name_type;
field_name_type const n = boost::fusion::at_c < 0 >(v);
typedef boost::fusion::result_of::at_c < field_value_type, 1 >::type field_data_type;
field_data_type const d = boost::fusion::at_c < 1 >(v);
std::cout << boost::mpl::c_str < remove_const_reference < field_name_type >::type >::value << " : " << d << std::endl;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用constRefFieldMap()函数,我会得到垃圾值或SIGSEGV.如果我直接调用boost :: fusion :: zip就可以完美地运行.这是输出......
EUR : 500
isoCode : EUR
rank : 500
Run Code Online (Sandbox Code Playgroud)
我之前看过这个问题 ......我在这里遇到了同样的问题吗?
编辑1:
提出我想要做的一个例子......
实际上......我正在尝试编写这样的代码.
MetaObject < Currency const > EUR_META(make_meta_object(EUR));
std::cout << get_field < std::string >("isoCode", EUR_META.constRefFieldMap()) << std::endl;
MetaObject < Currency > GBP_META(make_meta_object(GBP));
MutableRefFieldMap < Currency >::type const &fm = GBP_META.mutableRefFieldMap();
std::cout << set_field("rank", fm, 497) << std::endl;
Run Code Online (Sandbox Code Playgroud)
我可以通过字段名称调用的访问器和修饰符......
我计划编写一个精神解析器来解析JSON和XML并创建对象......在我的代码生成器的帮助下.主要思想是避免为每个对象生成解析代码,但仅针对那些使用过的对象,从而减少二进制大小.我现在有1000个物品.
我现在有这个工作.
不幸的是,这个问题没有引起更多的关注,但我猜大量的代码并没有多大帮助(这一点以及模板元编程不那么受欢迎的事实).
无论如何,你是对的,这是一个类似的问题.
问题是融合中的视图不会复制参数,它们只保留对它们的引用.这允许您通过中间体修改原始参数.
麻烦的是,在C++中,您被授权将临时绑定到const-reference,并将临时生命周期扩展为引用的生命周期.然而,这种行为不是传递性的,这导致了大量的麻烦.(Clang将尝试诊断这些情况,不幸的是第一个补丁失败了:p)
所以这里你的问题就在一行中:
return boost::fusion::zip(fieldNames < T >(), constRefFields(obj));
Run Code Online (Sandbox Code Playgroud)
fieldNames<T>() 创建一个临时的,绑定到const-reference,它的生命周期延长到表达式的结尾: ;快速修复:make fieldNames<T>()有一个本地静态变量并返回对此变量的引用,这将修复生命周期问题.
我仍然不明白你在尝试什么,所以我不能真正给出"更明智"的建议:)
| 归档时间: |
|
| 查看次数: |
859 次 |
| 最近记录: |