2013-04-30 13 views
7

To jest moje pierwsze pytanie do tej wielkiej wymiany wiedzy i mam nadzieję, że znajdę jakąś pomoc.Jak iterować nad boost :: fusion asocjacyjną strukturą i dostępem w ogólny sposób klucze

Próbuję wprowadzić ogólny sposób tworzenia funkcji PrintTo (później do wykorzystania w GoogleTest).

Poniższy kod wykonuje tylko połowę zlecenia. To tylko drukuje wartości zdefiniowanej struktury 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; 
} 

Więc co szukam jest sposobem drukowania automatycznie Foo::Keys również. Zajrzałem do wygenerowanego przez makro kodu BOOST_FUSION_DEFINE_ASSOC_STRUCT i o ile widzę Klawisze są dostępne jako static const char * boost :: fusion :: extension :: struct_member_name :: call().

Zajrzałem do kodu fusion :: for_each i do tej pory widzę tylko sposób na "skopiowanie" całego kodu, tak aby wywołanie fusion_printer_impl :: operator() zostało wywołane z dwoma parametrami: kluczem i wartościami. Zanim przejdę do tego kierunku, chciałbym wiedzieć, czy istnieją łatwiejsze sposoby, aby to osiągnąć.

Wiem, że możliwe jest zdefiniowanie explicite boost :: fusion :: map. Tutaj uzyskuje się automatycznie dostęp poprzez fuzję :: pair do typu klucza i wartości. Ale obecnie nie ma dla mnie opcji.

Tak więc każda pomoc tutaj jest mile widziany.

Odpowiedz

2

Yours jest dobre pytanie, mam nadzieję, że ktoś tu przyjdzie do czegoś czystsze niż to:

... 
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

Dzięki za odpowiedź. Pomogło mi to znacznie dalej. Zmieniając parametr result_type funktora na std :: string i przesyłając wynik frazy boost :: fusion :: iter_fold bezpośrednio do * os, mogę uniknąć _ugly_ const_cast. –

+0

Nawet o tym nie wspominając, zostawiając kogoś tam, aby jego dusza została zmiażdżona przez niezgłębione abstrakcje, a ponure mnóstwo błędów kompilatora byłoby bardzo nieludzkie ... – dsign

+0

Wiem, o czym mówisz. Przynajmniej VC10 i Clang znacznie się poprawiły. (Nie wiem o gcc). Mając błąd w korzystaniu z boost :: spirit sprawia zawsze radość :-( –

Powiązane problemy