【问题标题】:How to iterate over boost::fusion associative struct and access in a generic way the keys如何迭代 boost::fusion 关联结构并以通用方式访问键
【发布时间】:2013-04-30 13:34:20
【问题描述】:

这是我在这个伟大的知识交流中的第一个问题,我希望能找到一些帮助。

我尝试实现一种通用的方法来创建 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 的 makro 生成代码,据我所知,这些密钥可用作静态 const char* boost::fusion::extension::struct_member_name::call()。

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

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

因此,欢迎在这里提供任何帮助。

【问题讨论】:

    标签: c++ boost boost-fusion


    【解决方案1】:

    你的问题很好,希望这里有人能提出比这更干净的问题:

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

    【讨论】:

    • 感谢您的回答。它进一步帮助了我。通过将函子的 result_type 更改为 std::string 并将 boost::fusion::iter_fold 的结果直接流式传输到 *os 我可以避免 ugly const_cast.
    • 别提了,留下一个人在那里让他的灵魂被深不可测的抽象和可怕的编译器错误压垮是非常不人道的......
    • 我知道你在说什么。至少 VC10 和 Clang 进步了很多。 (我不知道 gcc)。使用 boost::spirit 时出错总是很有趣 :-(
    猜你喜欢
    • 1970-01-01
    • 2010-11-11
    • 2012-10-17
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 2020-08-26
    相关资源
    最近更新 更多