2010-11-30 9 views
0

私はフュージョンを試していて、非常に奇妙なものを見つけました...ここにコードがあります... ###########で問題のあるコードを強調表示しました# #####ブーストフュージョン奇妙

#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を直接呼び出すと、それは完全に機能します。ここでは、出力は私が前にこのquestionを見てきました...私はここに同じ問題に実行しています...

EUR : 500 
isoCode : EUR 
rank : 500 

あります?

EDIT 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を解析してオブジェクトを作成する精神パーサを書くことを計画しています。基本的な考え方は、すべてのオブジェクトの解析コードの生成を避けることですが、使用されたオブジェクトのみがバイナリサイズを減らすためです。私は今、1000個のオブジェクトを持っています。

私はこれを今働いています。

+1

あなたは最小限のテストケースを投稿し、より良いオフになっていると思いを与えることはできませんが、私は怖いですコードの大きな塊が人々を遠ざける:) –

答えて

7

この問題はもっと注意を引くものではありませんでしたが、コードの大部分が役に立たなかったと思います(テンプレートメタプログラミングがあまり一般的でないという事実)。

とにかく、そうです、それは同様の問題です。

ビューの融合では、は引数をコピーせず、参照のみを保持しています。これにより、元の引数を中間で変更することができます。

C++では、一時参照をconst-referenceにバインドする権限があり、一時的な有効期間は参照の有効期間に延長されるという問題があります。しかし、この動作は推移的ではなく、トラブルの重大な原因となっています。 (クランは、残念ながら最初のパッチが失敗し、それらの状況を診断しようとします:p)を

だからここにあなたの問題が1つの行に配置されています。

return boost::fusion::zip(fieldNames <T>(), constRefFields(obj)); 
  • fieldNames<T>()がバインドされている、一時的に作成し、 、それは生涯のconst参照です式の終わりまで延長されます。;
  • ビューを返したときに、一時的な寿命の期限が切れている、あなたはダングリング参照の上
を保持しています

クイック修正:にローカル静的変数を設定し、この変数への参照を返します。これにより、生涯の問題が修正されます。

私はまだあなたがが試みていたもの理解していないので、私は実際に「より賢明な」アドバイス:)

+0

+1のために* "私はコードの大部分があまり役に立たなかったと思う" * - それを掘り起こすために。 – peterchen

+0

@zrb:これはあなたが取り組んでいることを理解していますが、問題は、このすべてを読んで、達成しようとしていることを理解するのに時間がかかるため、あなたを助けてくれる人がいるかもしれないということです。私たちの方が簡単で、最小限のテストケースを公開した場合は、より多くの回答を得ることができます。これは問題を再現するコードの最小量です。とにかく、私が言及した "クイックフィックス"をテストしてください、私はあなたの問題を解決すべきだと思う。 –

+0

ありがとうございます。実際問題はconstRefFields()でした。私は今のところそれを取り組んだ。 – zrb