2013-04-30 32 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还有一种方式。我查看了makro生成的BOOST_FUSION_DEFINE_ASSOC_STRUCT代码,并且据我所见,Keys可以用作静态常量char * boost :: fusion :: extension :: struct_member_name :: call()。

我查看了fusion :: for_each的代码,到目前为止,我只看到一种方法来“复制”完整代码,以便用两个参数Key和values调用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。 – 2013-04-30 16:28:12

+0

甚至不要提到它,留下一个人让他的灵魂被深不可测的抽象和沉重的编译错误压垮会是非常不人道的...... – dsign 2013-04-30 18:57:50

+0

我知道你在说什么。至少VC10和Clang已经改善了很多。 (我不知道gcc)。在boost :: spirit的使用中出现错误总是很有趣:-( – 2013-04-30 20:59:35