2010-11-30 15 views
0

J'essaie Fusion et trouvé quelque chose de très étrange ... Voici le code ... J'ai mis en évidence le code problématique avec // ############ TROUBLE ICI # #####Boost fusion bizarrerie

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

Je reçois des valeurs de déchets ou SIGSEGV si j'utilise la fonction constRefFieldMap(). Si j'appelle directement boost :: fusion :: zip, cela fonctionne parfaitement. Voici la sortie ...

EUR : 500 
isoCode : EUR 
rank : 500 

J'ai regardé ce question plus tôt ... que je courais dans le même problème ici ???

EDIT 1:

Présenter un exemple de ce que je suis en train de faire ...

En fait ... Je suis en train d'écrire du code comme celui-ci.

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; 

accesseurs et modificateurs que je peux invoquer par des noms de terrain ...

je prévois d'écrire un analyseur d'esprit pour analyser XML JSON & et créer des objets ... avec l'aide de mes générateurs de code. L'idée principale est d'éviter de générer le code d'analyse pour chaque objet, mais seulement pour les objets qui sont utilisés et donc de réduire la taille binaire. J'ai des milliers d'objets maintenant.

Je travaille maintenant.

+1

Vous auriez été mieux que l'affichage d'un cas de test minimal, je crains de gros morceaux de code attirent les gens :) –

Répondre

7

Il est malheureux que cette question n'ait pas attiré plus d'attention, mais je suppose que le gros morceau de code n'a pas aidé beaucoup (cela et le fait que la métaprogrammation de modèle n'est pas si populaire).

De toute façon, vous avez raison, c'est un problème similaire.

Le problème est que les vues en fusion ne copient pas les arguments, ils ne gardent que des références à eux. Cela vous permet de modifier les arguments d'origine par leur intermédiaire.

Le problème est qu'en C++, vous êtes autorisé à lier un temporaire à une const-référence, et la durée de vie temporaire est étendue à celle de la référence. Cependant, ce comportement n'est pas transitif, ce qui a causé un gros problème de problèmes. (Clang tentera de diagnostiquer ces situations, malheureusement, le premier patch a échoué: p)

Voici donc votre problème se trouve dans une seule ligne:

return boost::fusion::zip(fieldNames <T>(), constRefFields(obj)); 
  • fieldNames<T>() crée un temporaire, qui est lié à const référence, il est durée de vie est prolongée jusqu'à la fin de l'expression: ;
  • lorsque vous retournez la vue, la durée de vie temporaire a expiré, vous tenez sur une référence boiteuse

Correction rapide: make fieldNames<T>() avoir une variable statique locale et retourner une référence à cette variable, cela va résoudre le problème de durée de vie.

Je n'ai toujours pas compris ce que vous tentiez, donc je ne peux pas vraiment donner « plus sensible » des conseils :)

+0

+1 déjà pour * "Je suppose que le gros morceau de code n'a pas aidé beaucoup" * - et pour le creuser. – peterchen

+0

@zrb: Je comprends que c'est ce sur quoi vous travaillez, mais le problème est que les gens qui peuvent vous aider à vous détourner probablement parce qu'il faut du temps pour lire tout cela et comprendre ce que vous essayez d'atteindre. Ce serait plus facile pour nous, et vous auriez ainsi plus de réponses si vous publiiez un cas de test minimal: c'est la quantité minimale de code qui reproduit le problème. Quoi qu'il en soit, faites le test de la "solution rapide" dont j'ai parlé, je pense que cela devrait résoudre votre problème. –

+0

Merci. Le problème était en fait avec constRefFields(). J'ai travaillé autour de ça maintenant. – zrb