2010-11-30 9 views
0

Ich versuche Fusion und fand etwas sehr merkwürdig ... Hier ist der Code ... Ich habe den problematischen Code mit hervorgehoben // ############ HIER ### #####Boost Fusion Kuriosität

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

ich Müll Werte oder SIGSEGV, wenn ich die constRefFieldMap() Funktion verwenden. Wenn ich boost :: fusion :: zip direkt anrufe, funktioniert das perfekt. Hier ist die Ausgabe ...

EUR : 500 
isoCode : EUR 
rank : 500 

Ich habe in diesem question sah früher ... bin ich in das gleiche Problem laufen hier ???

EDIT 1:

Presenting ein Beispiel von dem, was ich zu tun versuchen ...

Eigentlich ... Ich versuche, Code wie diesen zu schreiben.

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; 

Zugriffs- und Modifikatoren, die ich von Feldnamen aufrufen können ...

Ich plane einen Geist Parser schreiben JSON & XML zu analysieren und Objekte erstellen ... mit etwas Hilfe von meinem Code-Generatoren. Die Grundidee besteht darin, zu vermeiden, dass der Parsing-Code für jedes Objekt erzeugt wird, sondern nur für die Objekte, die verwendet werden und somit die Binärgröße reduzieren. Ich habe jetzt 1000 Objekte.

Ich habe das jetzt funktioniert.

+1

Sie besser dran, nur einen minimalen Testfalls Entsendung gewesen sein würden, fürchte mich, große Teile des Codes ziehen Leute weg :) –

Antwort

7

Es ist bedauerlich, dass diese Frage nicht mehr Aufmerksamkeit auf sich zog, aber ich denke, der große Brocken Code hat nicht viel geholfen (das und die Tatsache, dass Template-Metaprogrammierung nicht so populär ist).

Wie auch immer, Sie haben Recht, es ist ein ähnliches Problem.

Das Problem ist, dass die Ansichten in Fusion die Argumente nicht kopieren, sie nur Referenzen auf sie zu halten. Auf diese Weise können Sie die ursprünglichen Argumente nach ihrem Intermediate ändern.

Das Problem ist, dass Sie in C++ berechtigt sind, ein temporäres an eine const-Referenz zu binden, und die temporäre Lebensdauer wird auf die der Referenz erweitert. Dieses Verhalten ist jedoch nicht transitiv, was zu einer Häufung von Problemen geführt hat. (Clang versuchen, solche Situationen zu diagnostizieren, leider ist die erste Patch ist fehlgeschlagen: p)

Also hier Ihr Problem in einer einzigen Zeile befindet:

return boost::fusion::zip(fieldNames <T>(), constRefFields(obj)); 
  • fieldNames<T>() erstellt einen temporären, ist, dass gebunden eine const-Referenz, es ist Lebenszeit bis zum Ende des Ausdrucks erweitert: ;
  • wenn Sie die Ansicht zurückzukehren, hat die temporäre Lebensdauer abgelaufen ist, werden Sie auf eine baumelnde Referenzhalte

Schnellkorrektur: make haben eine lokale statische Variable und geben einen Verweis auf diese Variable zurück, dies wird das Lebensdauerproblem beheben.

Ich habe noch nicht verstanden, was Sie aber versuchen, so kann ich nicht wirklich geben „vernünftige“ Beratung :)

+0

+1 bereits für für * "Ich denke, dass der große Block des Codes nicht viel half" * - und dafür graben. – peterchen

+0

@zrb: Ich verstehe, dass das ist, woran Sie arbeiten, aber das Problem ist, dass Leute, die Ihnen helfen können, sich wahrscheinlich abwenden, weil es Zeit braucht, all dies durchzulesen und zu verstehen, was Sie erreichen wollen. Es wäre einfacher für uns, und Sie würden somit mehr Antworten erhalten, wenn Sie einen minimalen Testfall veröffentlichen würden: Das ist die minimale Menge Code, die das Problem reproduziert. Wie auch immer, teste die "Quickfix", die ich erwähnt habe, ich denke, es sollte dein Problem lösen. –

+0

Danke. Das Problem war eigentlich mit constRefFields(). Ich habe jetzt daran gearbeitet. – zrb