提升Karma,重新排序结构元素

时间:2018-02-06 15:07:33

标签: c++ boost boost-spirit

说我有这样的结构:

struct MyStruct
{
    int a;
    int b; 
    int c;
}

BOOST_FUSION_ADAPT_STRUCT
(
    MyStruct,
    (int, a)
    (int, b)
    (int, c)
)

然后如果我有一个简单的发电机:

struct MyStructGenerator
    : boost::spirit::karma::grammar<boost::spirit::ostream_iterator, MyStruct()>
{
    MyStructGenerator() : MyStructGenerator::base_type(start_)
    {

        namespace bsk = boost::spirit::karma;

        start_ = '<' 
            << bsk::int_
            << ','
            << bsk::int_
            << ','
            << bsk::int_
            << '>';
    }

    ~MyStructGenerator() = default;
    boost::spirit::karma::rule<boost::spirit::ostream_iterator, MyStruct()> start_;
};

我运行以下内容:

int main()
{
    MyStruct ms = { 3, 2, 1 };
    std::cout << boost::spirit::karma::format(MyStructGenerator(), ms) << std::endl;
}

我当然希望看到<3, 2, 1>。我无法弄清楚如何改变规则内的顺序?如果我想查看<1, 2, 3>或即使我想查看<2, 1, 3>该怎么办?

另外,无论如何我可以在没有BOOST_FUSION_ADAPT_STRUCT的情况下执行此操作吗?

2 个答案:

答案 0 :(得分:3)

Q1 如果我想看到&lt; 1,2,3&gt;或者即使我想看{4}}

只需更改适应的订单:

简化 Live On Wandbox

<2, 1, 3>

打印#include <boost/fusion/adapted/struct.hpp> struct MyStruct { int a, b, c; }; BOOST_FUSION_ADAPT_STRUCT(MyStruct, a, b, c) #include <boost/spirit/include/karma.hpp> namespace bsk = boost::spirit::karma; template <typename It = boost::spirit::ostream_iterator> struct MyGen : bsk::grammar<It, MyStruct()> { MyGen() : MyGen::base_type(start_) { using namespace bsk; start_ = '<' << int_ << ',' << int_ << ',' << int_ << '>'; } private: bsk::rule<It, MyStruct()> start_; }; int main() { MyGen<> gen; std::cout << format(gen, MyStruct { 3, 2, 1 }) << "\n"; } ,但

<3,2,1>

打印BOOST_FUSION_ADAPT_STRUCT(MyStruct, c, b, a)

Q2没有适应?

好。我可以向您展示一些您可能感兴趣的事情:

    没有业力的
  1. Live On Wandbox

    <1,2,3>

    打印

    #include <boost/fusion/adapted/struct.hpp>
    
    struct MyStruct { int a, b, c; };
    BOOST_FUSION_ADAPT_STRUCT(MyStruct, c, b, a)
    
    #include <iostream>
    #include <boost/fusion/include/io.hpp>
    #include <boost/fusion/include/as_vector.hpp>
    using boost::fusion::as_vector;
    
    int main() {
        MyStruct ms { 3, 2, 1 };
        std::cout << as_vector(ms) << "\n";
    
        std::cout 
            << boost::fusion::tuple_open("<")
            << boost::fusion::tuple_delimiter(",")
            << boost::fusion::tuple_close(">");
    
        std::cout << as_vector(ms) << "\n";
    }
    
  2. 命名改编:您可以使用(1 2 3) <1,2,3> 宏同时调整的不同订单。这是一个使用Fusion IO和Karma生成器演示的演示。

      

    注意我稍微修改了结构,因此更容易跟踪哪个字段为*_NAMED'a''b'

    查看 Live On Wandbox

    'c'

    打印

    #include <boost/fusion/adapted/struct.hpp>
    
    struct MyStruct { char a, b, c; };
    BOOST_FUSION_ADAPT_STRUCT_NAMED(MyStruct, AsABC, a, b, c)
    BOOST_FUSION_ADAPT_STRUCT_NAMED(MyStruct, AsBCA, b, c, a)
    BOOST_FUSION_ADAPT_STRUCT_NAMED(MyStruct, AsCBA, c, b, a)
    
    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/qi.hpp>
    namespace bsk = boost::spirit::karma;
    
    template <typename Attr, typename It = boost::spirit::ostream_iterator>
    struct MyGen : bsk::grammar<It, Attr()> {
        MyGen() : MyGen::base_type(start_) {
            using namespace bsk;
            start_ = '<' << auto_ << ',' << auto_ << ',' << auto_ << '>';
        }
      private:
        bsk::rule<It, Attr()> start_;
    };
    
    #include <iostream>
    #include <boost/fusion/include/io.hpp>
    #include <boost/fusion/include/as_vector.hpp>
    using boost::fusion::as_vector;
    
    template <typename Attr>
    void do_tests(Attr const& ms) {
        std::cout << as_vector(ms) << "\n";
        std::cout << format(MyGen<Attr>{}, ms) << "\n";
    }
    
    int main() {
        std::cout << boost::fusion::tuple_open("<") << boost::fusion::tuple_delimiter(",") << boost::fusion::tuple_close(">");
    
        MyStruct ms { 'a', 'b', 'c' };
    
        using namespace boost::fusion::adapted;
        do_tests(AsABC{ms});
        do_tests(AsCBA{ms});
        do_tests(AsBCA{ms});
    }
    
  3. 是的,你可以不做适应(不要):

    Live On Wandbox (由于编译时限制而评论部分)

    <a,b,c>
    <a,b,c>
    <c,b,a>
    <c,b,a>
    <b,c,a>
    <b,c,a>
    

    打印

    struct MyStruct { char a, b, c; };
    
    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    namespace bsk = boost::spirit::karma;
    namespace phx = boost::phoenix;
    
    template <typename It = boost::spirit::ostream_iterator>
    struct MyGen : bsk::grammar<It, MyStruct()> {
        MyGen() : MyGen::base_type(start_) {
            using boost::proto::deep_copy;
            using namespace bsk;
            auto A = deep_copy(char_[ _1 = phx::bind(&MyStruct::a, _val) ]);
            auto B = deep_copy(char_[ _1 = phx::bind(&MyStruct::b, _val) ]);
            auto C = deep_copy(char_[ _1 = phx::bind(&MyStruct::c, _val) ]);
            start_ =
                '<' << A << ',' << B << ',' << C << '>' << eol <<
                '<' << A << ',' << C << ',' << B << '>' << eol <<
                '<' << B << ',' << A << ',' << C << '>' << eol <<
                '<' << C << ',' << A << ',' << B << '>' << eol <<
                '<' << B << ',' << C << ',' << A << '>' << eol <<
                '<' << C << ',' << B << ',' << A << '>' << eol
                ;
        }
      private:
        bsk::rule<It, MyStruct()> start_;
    };
    
    int main() {
        std::cout << format(MyGen<>{}, MyStruct { 'a', 'b', 'c' });
    }
    

答案 1 :(得分:2)

您可以简单地使用phoenix和bind来访问成员值。 因此,对于您交换成员的示例,它将是这样的:

#include <iostream>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/phoenix/bind/bind_member_variable.hpp>
using namespace std;
struct MyStruct {
    int a;
    int b; 
    int c;
};

struct MyStructGenerator : boost::spirit::karma::grammar<boost::spirit::ostream_iterator, MyStruct()>
{
    MyStructGenerator() : MyStructGenerator::base_type(start_)
    {
        namespace bsk = boost::spirit::karma;
        start_ = '<' 
            << bsk::int_[bsk::_1 = boost::phoenix::bind(&MyStruct::c, bsk::_val)]
            << ','
            << bsk::int_[bsk::_1 = boost::phoenix::bind(&MyStruct::b, bsk::_val)]
            << ','
            << bsk::int_[bsk::_1 = boost::phoenix::bind(&MyStruct::a, bsk::_val)]
            << '>';
    }

    ~MyStructGenerator() = default;
    boost::spirit::karma::rule<boost::spirit::ostream_iterator, MyStruct()> start_;
};

int main() {
    MyStruct ms = { 3, 2, 1 };
    std::cout << boost::spirit::karma::format(MyStructGenerator(), ms) << std::endl;
}