2013-04-30 2 views
7

Это мой первый вопрос в этом большом обмене знаниями, и я надеюсь, что нахожу помощь.Как итерации по boost :: fusion ассоциативной структуре и доступу в общем виде ключи

Я пытаюсь реализовать общий способ создания функций PrintTo (позже будет использоваться в GoogleTest).

Таким образом, следующий код выполняет только половину задания. Он печатает только значения заданной структуры 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; 
} 

Так что я ищу способ автоматически распечатывает Foo::Keys, а также. Я заглянул в генерируемый макром код BOOST_FUSION_DEFINE_ASSOC_STRUCT, и, насколько я вижу, ключи доступны как static const char * boost :: fusion :: extension :: struct_member_name :: call().

Я изучил код fusion :: for_each, и до сих пор я вижу только способ «реплицировать» полный код, чтобы был вызван fusion_printer_impl :: operator() с двумя параметрами: ключ и значения. Прежде чем я пойду в этом направлении, я хотел бы знать, есть ли более простые способы для этого.

Я знаю, что можно определить явный boost :: fusion :: map. Здесь вы получаете автоматический доступ через fusion :: pair к типу и значению Key. Но в настоящее время это не вариант для меня.

Так что любая помощь здесь приветствуется.

ответ

2

Ваш хороший вопрос, надеюсь, кто-то здесь придет к чему-то чище, чем это:

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

Спасибо за ответ. Это помогло мне намного дальше. Изменяя result_type функтора на std :: string и передавая результат boost :: fusion :: iter_fold непосредственно в * os, я могу избежать _ugly_ const_cast. –

+0

Даже не упоминайте об этом, оставив кого-то там, чтобы его душа сокрушилась непостижимыми абстракциями, и мрачные нагрузки ошибок компилятора были бы очень бесчеловечными ... – dsign

+0

Я знаю, о чем вы говорите. По крайней мере, VC10 и Clang значительно улучшились. (Я не знаю о gcc). Ошибка при использовании boost :: spirit делает всегда весело :-( –