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

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;

フィールド名で呼び出すことができるアクセサーと修飾子...

JSON と XML を解析してオブジェクトを作成するためのスピリット パーサーを作成する予定です...コード ジェネレーターの助けを借りて。主なアイデアは、すべてのオブジェクトに対して解析コードを生成することを回避することですが、使用されるオブジェクトに対してのみ生成し、バイナリ サイズを縮小することです。私は今、何千ものオブジェクトを持っています。

私は今これを機能させました。

4

1 に答える 1

7

この質問があまり注目されなかったのは残念ですが、コードの大部分はあまり役に立たなかったと思います (それと、テンプレートのメタプログラミングがあまり普及していないという事実も)。

とにかく、あなたは正しいです、それは同様の問題です。

問題は、フュージョンのビューが引数をコピーせず、それらへの参照のみを保持することです。これにより、元の引数を中間で変更できます。

問題は、C++ では、一時を const 参照にバインドする権限があり、一時的な有効期間が参照の有効期間まで延長されることです。ただし、この動作は推移的ではないため、多くの問題が発生しています。(Clang はこれらの状況を診断しようとしますが、残念ながら最初のパッチは失敗しました:p)

したがって、ここで問題は1行にあります。

return boost::fusion::zip(fieldNames < T >(), constRefFields(obj));
  • fieldNames<T>()const 参照にバインドされた一時的なものを作成し、その有効期間は式の終わりまで延長されます。;
  • ビューを返すと、一時的な有効期限が切れ、ぶら下がっている参照を保持しています

簡単な修正:fieldNames<T>()ローカルの静的変数を作成し、この変数への参照を返すと、有効期間の問題が修正されます。

私はまだあなたが何をしようとしているのか理解していないので、「より賢明な」アドバイスをすることはできません:)

于 2010-12-01T07:32:24.580 に答える