2013-04-30 12 views
7

Dies ist meine allererste Frage in diesen großen Wissensaustausch und ich hoffe, ich finde etwas Hilfe.Wie iterate über boost :: fusion assoziative Struktur und Zugriff in einer generischen Weise die Schlüssel

Ich versuche, eine generische Möglichkeit zum Erstellen von PrintTo-Funktionen zu implementieren (später in GoogleTest verwendet werden).

So macht der folgende Code nur die Hälfte der Arbeit. Er druckt nur die Werte der definierten Struktur Foo::Bar

#include <iostream> 
#include <sstream> 
#include <string> 

#include <boost/fusion/container.hpp> 
#include <boost/fusion/algorithm.hpp> 
#include <boost/fusion/adapted/struct/define_assoc_struct.hpp> 
#include <boost/fusion/include/define_assoc_struct.hpp> 

namespace Foo 
{ 
    namespace Keys 
    { 
    struct StringField; 
    struct IntField; 
    }; 
} 

BOOST_FUSION_DEFINE_ASSOC_STRUCT(
    (Foo), Bar, 
    (std::string, stringField, Foo::Keys::StringField) 
    (int,   intField, Foo::Keys::IntField)) 


struct fusion_printer_impl 
{ 
    std::ostream& _os; 

    fusion_printer_impl(std::ostream& os) 
    : _os(os) {} 

    template <typename T> 
    void operator() (T& v) const 
    { 
    _os << v << std::endl; 
    } 
}; 

void PrintTo(Foo::Bar const& v, std::ostream* os) 
{ 
    boost::fusion::for_each(v, fusion_printer_impl(*os)); 
} 

int main() 
{ 
    Foo::Bar fb("Don't panic!", 42); 
    std::ostringstream temp; 

    PrintTo(fb, &temp); 

    std::cout << temp.str() << std::endl; 
} 

Also, was ich bin auf der Suche nach einer Möglichkeit, automatisch die Foo::Keys und zu drucken. Ich habe in den Makro-generierten Code von BOOST_FUSION_DEFINE_ASSOC_STRUCT geschaut und soweit ich sehen kann, sind die Schlüssel als statisches const char * boost :: fusion :: extension :: struct_member_name :: call() verfügbar.

Ich schaute in den Code der Fusion :: for_each und ich bis jetzt sehe ich nur eine Möglichkeit, den vollständigen Code zu replizieren, so dass fusion_printer_impl :: operator() wurde mit zwei Parametern, Schlüssel und Werte aufgerufen. Bevor ich in diese Richtung gehe, würde ich gerne wissen, ob es leichtere Möglichkeiten gibt, dies zu erreichen.

Ich weiß, dass es möglich ist, eine boost :: fusion :: map explizit zu definieren. Hier bekommt man automatisch Zugriff über das fusion :: pair to Key type und value. Aber das ist derzeit keine Option für mich.

Also jede Hilfe hier ist willkommen.

Antwort

2

Yours ist eine gute Frage, hoffentlich hier jemand etwas sauberer als das kommen wird:

... 
struct fusion_printer_2 
{ 
    typedef std::ostream* result_type; 

    // Well, not really the intented use but... 
    template<typename T> 
    std::ostream* operator()(std::ostream const* out, const T& t) const 
    { 
     std::ostream* const_violated_out = const_cast<result_type>(out); 
     (*const_violated_out) << 
      (std::string(typeid(typename boost::fusion::result_of::key_of<T>::type).name()) + ": " + boost::lexical_cast<std::string>(deref(t))) << std::endl; 
     return const_violated_out; 
    } 
}; 

void PrintTo(Foo::Bar const& v, std::ostream* os) 
{ 
    boost::fusion::iter_fold(v, os, fusion_printer_2()); 
} 
... 
+1

Danke für die Antwort. Es hat mir sehr geholfen. Indem ich den result_type des funktors in std :: string ändere und das Ergebnis von boost :: fusion :: iter_fold direkt in * os streame, kann ich den _ugly_ const_cast vermeiden. –

+0

Erwähne es nicht einmal, lass jemanden da raus, der seine Seele durch unergründliche Abstraktionen und grimmige Lasten von Compiler-Fehlern zerquetscht hat. Das wäre sehr unmenschlich ... – dsign

+0

Ich weiß wovon du sprichst. Zumindest VC10 und Clang haben sich sehr verbessert. (Ich weiß nicht über gcc). Fehler bei der Benutzung von boost :: spirit machen immer Spaß :-( –