如何迭代boost :: fusion关联结构并以通用方式访问键

时间:2013-04-30 13:34:20

标签: c++ boost 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可用作static const char * boost :: fusion :: extension :: struct_member_name :: call()。

我查看了fusion :: for_each的代码,到目前为止,我只看到了一种'复制'完整代码的方法,以便使用两个参数Key和值调用fusion_printer_impl :: operator()。在我走向这个方向之前,我想知道是否有更简单的方法来实现这一目标。

我知道可以定义一个显式的boost :: fusion :: map。这里可以通过fusion :: pair自动访问Key类型和值。但这对我来说目前没有选择。

所以欢迎任何帮助。

1 个答案:

答案 0 :(得分:3)

你的问题是一个很好的问题,希望这里有人会比这更清洁:

...
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());
}
...