增强融合奇异性

发布于 2024-10-05 23:15:51 字数 7010 浏览 6 评论 0原文

我正在尝试 Fusion 并发现一些非常奇怪的东西...这是代码...我用 // ############ TROUBLE HERE ######

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

I 突出显示了有问题的代码如果我使用 constRefFieldMap() 函数,则会获取垃圾值或 SIGSEGV。如果我直接调用 boost::fusion::zip ,它就可以完美工作。这是输出...

EUR : 500
isoCode : EUR
rank : 500

我看过这个 问题之前...我在这里遇到了同样的问题吗???

编辑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;

我可以通过字段名称调用的访问器和修饰符...

我计划编写一个 Spirit 解析器来解析 JSON 和XML 并创建对象...在我的代码生成器的帮助下。主要思想是避免为每个对象生成解析代码,而只为那些被使用的对象生成解析代码,从而减少二进制大小。我现在有 1000 个对象。

我现在已经开始工作了。

I am trying out Fusion and found something very odd... Here is the code... I have highlighted the problematic code with // ############ TROUBLE HERE ######

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

I get garbage values or SIGSEGV if I use the constRefFieldMap() function. If I call boost::fusion::zip directly it works perfectly. Here is the output...

EUR : 500
isoCode : EUR
rank : 500

I have looked at this question earlier... am I running into the same problem here???

EDIT 1:

Presenting an example of what I am trying to do...

Actually... I am trying to write code like this.

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;

Accessors and modifiers that I can invoke by field names...

I plan to write a spirit parser to parse JSON & XML and create objects... with some help from my code generators. The main idea is to avoid generating the parsing code for every object, but only for those objects that get used and hence reduce the binary size. I have 1000s of objects now.

I have got this working now.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

勿忘初心 2024-10-12 23:15:51

不幸的是这个问题没有引起更多的关注,但我想大量的代码并没有多大帮助(事实上模板元编程并不那么流行)。

不管怎样,你是对的,这是一个类似的问题。

问题是融合中的视图不会复制参数,它们只保留对参数的引用。这允许您通过中间参数修改原始参数。

问题在于,在 C++ 中,您有权将临时变量绑定到 const 引用,并且临时变量的生命周期会延长到引用的生命周期。然而这种行为是不可传递的,这导致了很多麻烦。 (Clang 将尝试诊断这些情况,不幸的是第一个补丁失败了:p)

所以这里你的问题位于一行:

return boost::fusion::zip(fieldNames < T >(), constRefFields(obj));
  • fieldNames() 创建一个临时的,它绑定到const-reference,它的生命周期会延长,直到表达式结束: ;
  • 当您返回视图时,临时生命周期已过期,您将保留一个悬空引用

快速修复:make fieldNames() 有一个局部静态变量并返回对此变量的引用,这将解决生命周期问题。

我仍然不明白你在尝试什么,所以我不能真正给出“更明智”的建议:)

It's unfortunate this question didn't draw more attention, but I guess the large chunk of code didn't help much (that and the fact that template metaprogramming is not so popular).

Anyway, you're right, it's a similar issue.

The problem is that the views in fusion do not copy the arguments, they only keep references to them. This allows you to modify the original arguments by their intermediate.

The trouble is that in C++ you are authorized to bind a temporary to a const-reference, and the temporary lifetime is extended to that of the reference. However this behavior is not transitive, which has caused a heapload of troubles. (Clang will attempt to diagnose those situations, unfortunately the first patch failed :p)

So here your problem is located in one single line:

return boost::fusion::zip(fieldNames < T >(), constRefFields(obj));
  • fieldNames<T>() creates a temporary, that is bound to a const-reference, it's lifetime is extended until the end of the expression: ;
  • when you return the view, the temporary lifetime has expired, you're holding onto a dangling reference

Quick fix: make fieldNames<T>() have a local static variable and return a reference to this variable, this will fix the lifetime issue.

I still haven't understood what you were attempting though, so I can't really give "more sensible" advice :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文