BOOST_FUSION_ADAPT_STRUCT的限制

时间:2013-11-27 12:01:26

标签: c++ metaprogramming boost-fusion

我尝试使用BOOST_FUSION_ADAPT_STRUCT宏并尝试了一些天真的东西,例如使用Fusion来打印任意结构。

从这个example code given in the documentation开始,我无法在我的自适应结构上执行融合序列允许的一些操作。

#include <boost/fusion/adapted.hpp>
#include <boost/fusion/sequence/io/out.hpp>
#include <boost/fusion/sequence/intrinsic.hpp>
#include <boost/fusion/view.hpp>
#include <iostream>

namespace fuz = boost::fusion;

namespace demo
{
    struct employee
    {
        std::string name;
        int age;
    };
}

// demo::employee is now a Fusion sequence
BOOST_FUSION_ADAPT_STRUCT(
    demo::employee,
    (std::string, name)
    (int, age))

int main()
{
    // tried to initialize an employee like a fusion sequence
    // but it didnt work
    // demo::employee e("bob", 42);

    demo::employee e;
    e.name = "bob";
    e.age = 42;

    // Access struct members with fusion random access functions
    // ok
    std::cout << fuz::at_c<0>(e) << std::endl; 

    // tried to print the struct like any othe fusion sequence
    // didnt work
    // std::cout << e << std::endl;

    // I made it work by using a fusion view
    // is it the right way?
    std::cout << fuz::as_nview<0, 1>(e) << std::endl;
}

这引出了以下问题:

  • 为什么Fusion magik不在这里运作?

  • 使用视图是打印适应结构的正确方法吗?

  • 改编后的结构可以用多远作为融合序列?

2 个答案:

答案 0 :(得分:9)

来自boost::fusion文档:

  

I / O运算符在命名空间boost :: fusion

中被重载

这意味着如果您想要隐式集成这些operator<<,则需要在当前命名空间中注入boost::fusion命名空间(此处为::),或者明确使用它们。

总结一下,添加:

using namespace boost::fusion;

应该适用于您的情况。 或者为明确使用,您必须写:

boost::fusion::operator<<(std::cout, e) << std::endl;

---编辑---

稍微阅读boost::fusion的代码之后,由于boost::fusion::operators::operator<< Koenig的查找,您似乎感到困惑,如果您的参数是真实的,则选择boost::fusion::sequence boost::fusion

这就是为什么您不需要注入boost::fusion::operator<<命名空间,也不需要为boost::fusion命名空间中定义的类型显式调用boost/fusion/sequence/io/out.hpp

一些解释:

我不会在这里解释Koenig的查找(也称为Argument Dependent Lookup - ADL)的整个概念,因为这不是重点,但基本上,它表明如果你使用的是一个类型为的变量在命名空间内,函数查找扩展到该参数的命名空间。

在这种特殊情况下,包含boost::fusion::operator::operator<<的{​​{1}}将定义boost::fusion,然后将其注入$ cat /usr/local/include/boost/fusion/sequence/io/out.hpp [...] namespace boost { namespace fusion { [...] namespace operators { template <typename Sequence> inline typename boost::enable_if< fusion::traits::is_sequence<Sequence> , std::ostream& >::type // this is just a SFINAE trick to ensure // the function will only be selected for // actual boost::fusion::sequence operator<<(std::ostream& os, Sequence const& seq) { return fusion::out(os, seq); // this will print out the sequence } } using operators::operator<<; // here the operator<< is injected // in boost::fusion }} 命名空间。

operator<<

这意味着使用 boost::fusion 调用其类型位于 operator<< 命名空间中的参数将找到正确的重载。< /强>

使用类型不在此命名空间中的参数调用将无法解决boost::fusion的正确重载(在您的示例中就是这种情况)。

您可以通过在namespace boost { namespace fusion { struct employee { std::string name; int age; }; }} BOOST_FUSION_ADAPT_STRUCT( boost::fusion::employee, (std::string, name) (int, age)) [...] boost::fusion::employee e; std::cout << e << std::endl; // ADL will work here 命名空间中定义类型来检查。

gdb

附注:如果要调试这些名称查找问题,则应使用$ cat fusion.cpp #include <iostream> #include <cstdlib> #include <boost/fusion/container/vector.hpp> #include <boost/fusion/sequence/io.hpp> int main(int, char**) { boost::fusion::vector<int, char> foo(42, '?'); std::cout << foo << std::endl; return EXIT_SUCCESS; } $ gdb -q ./fusion Reading symbols for shared libraries ... done (gdb) b 10 Breakpoint 1 at 0x1000012f7: file fusion.cpp, line 10. (gdb) r Starting program: /Users/avallee/Projects/tmp/fusion Reading symbols for shared libraries ++............................. done Breakpoint 1, main (unnamed_arg=0x7fff5fbffb60, unnamed_arg=0x7fff5fbffb60) at fusion.cpp:10 10 std::cout << foo << std::endl; (gdb) s boost::fusion::operators::operator<< <boost::fusion::vector<int, char, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > (os=@0x7fff762b5f10, seq=@0x7fff5fbffb18) at out.hpp:38 38 return fusion::out(os, seq); 。这样,您将始终知道选择了哪个过载。在这种情况下:

{{1}}

答案 1 :(得分:4)

非常感谢Aurelien提供的详细解释。我还在Google群组中找到了this post。正如您的解释所导致的那样,最简单的方法是将它放在演示命名空间中:

namespace demo{
    using boost::fusion::operators::operator<<;
    ...