获取的boost ::精神::气使用STL容器 [英] Getting boost::spirit::qi to use stl containers

查看:101
本文介绍了获取的boost ::精神::气使用STL容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图解析与boost.spirit的气库的东西,我运行到一个问题。根据本<一href=\"http://www.boost.org/doc/libs/1_54_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/operator.html\"相对=nofollow>精神文档, A&GT;&GT; b 应该产生与该类型的东西元组LT; A,B&GT; 。但是,这是一个的boost ::元组(又名融合向量),而不是一个的std ::元组(我想)。

I'm trying to parse something with boost.spirit's qi library, and I'm running into an issue. According to the spirit docs, a >> b should produce something with the type tuple<A, B>. But this is a boost::tuple (aka fusion vector), and not a std::tuple (which I want).

有没有简单的方法,使的boost ::元组 => 的std ::元组

Is there any easy way to make this conversion between boost::tuple => std::tuple?

在同一个文件页面说 *一个应该产生与该类型的东西矢量&lt; A&GT; 。这似乎是一个生成一个的std ::矢量&lt; A&GT; (或某种的boost ::矢量&lt;一&GT; 可隐式转换为的std ::矢量&lt; A&GT; )。我只是想知道这是否相同的行为是可用于元组。

The same documentation page says that *a should produce something with the type vector<A>. This seems to be producing a std::vector<A> (or some kind of boost::vector<A> that can implicitly convert to a std::vector<A>). I just wanted to know if this same behavior was available for tuples.

推荐答案

答案很简单:

使用的#include&LT;升压/融合/调整/ std_tuple.hpp方式&gt;

更完整的答案:

正如你所看到的here:

在属性表中,我们将使用矢量&lt; A&GT; 元组LT; A,B ...&GT; 只用作占位符。的标记矢量&lt; A&GT; 表示A型的任何STL容器保持元件和符号元组LT; A,B ...&GT; 为持有A,B任何Boost.Fusion序列,...等元素。最后,未使用的为看台unused_type。

In the attribute tables, we will use vector<A> and tuple<A, B...> as placeholders only. The notation of vector<A> stands for any STL container holding elements of type A and the notation tuple<A, B...> stands for any Boost.Fusion sequence holding A, B, ... etc. elements. Finally, Unused stands for unused_type.

所以,当一个解析器/发电机具有元组LT的属性; A,B ...&GT; 你可以使用任何的融合序列(如融合::向量或融合::列表)或者任何可以(如的boost ::数组的boost ::元组的std ::对,性病::元组,你自己的使用结构BOOST_FUSION_ADAPT_STRUCT)适应融合序列。

So when a parser/generator has an attribute of tuple<A,B...> you can use any fusion sequence (such as fusion::vector or fusion::list) or anything that can be adapted to a fusion sequence (such as boost::array, boost::tuple, std::pair, std::tuple, your own struct using BOOST_FUSION_ADAPT_STRUCT).

和当它有矢量&lt; A&GT; 您可以使用std :: vector的,性病::名单,甚至性病::地图,如果你的元素是对的。您也可以使用自己的结构,如果你还专门定制的几个点(至少is_container,container_value和push_back_container在boost ::精神特质::)。

And when it has vector<A> you can use std::vector, std::list, and even std::map if your elements are pairs. You can also use your own struct if you also specialize several customization points (at least is_container, container_value and push_back_container in boost::spirit::traits).

的std ::对结果
为了能够使用的std ::对与精神,你只需要添加一个头:

std::pair
In order to be able to use std::pair with spirit you just need to add a single header:

#include <boost/fusion/include/std_pair.hpp>
...
qi::rule<Iterator,std::pair<int,double>()> rule = 
    qi::int_ >> qi::lit(',') >> qi::double_;

的std ::元组结果
与升压1.48.0开始,你可以的std ::元组做相同的:

std::tuple
Starting with boost 1.48.0 you can do the same for std::tuple:

#include <boost/fusion/adapted/std_tuple.hpp> 
...
qi::rule<Iterator,std::tuple<int,std::string,double>()> rule =
    qi::int_ >> qi::lit(',') >> +~qi::char_(',') >> qi::lit(',') >> qi::double_;

您自己的结构结果
您可以BOOST_FUSION_ADAPT_STRUCT的帮助下很容易适应您的自定义结构:

Your own struct
You can adapt your custom struct very easily with the help of BOOST_FUSION_ADAPT_STRUCT:

#include <boost/fusion/include/adapt_struct.hpp>
...
struct normal_struct
{
    int integer;
    double real;
};

BOOST_FUSION_ADAPT_STRUCT(
    normal_struct,
    (int, integer)
    (double, real)
)
...
qi::rule<Iterator,normal_struct()> rule =
    qi::int_ >> qi::lit(',') >> qi::double_;

有一个已知的限制不过,当您尝试使用具有这也是一个容器编译单个元素的结构失效,除非你添加齐:: EPS&GT;&GT; ... 你的规则。

There is one known limitation though, when you try to use a struct that has a single element that is also a container compilation fails unless you add qi::eps >> ... to your rule.

struct struct_with_single_element_container
{
    std::vector<int> cont;
};

BOOST_FUSION_ADAPT_STRUCT(
    struct_with_single_element_container,
    (std::vector<int>, cont)
)
...
qi::rule<Iterator,struct_with_single_element_container()> rule =
    qi::eps >> qi::int_%qi::lit(',');

的std ::地图结果
你可以简单地使用std ::地图为性病::对的容器。但请记住,如果有重复按键在输入,只有第一个将被插入到地图(如果你使用多重映射一切都会被插入当然):

std::map
You can simply use std::map as a container of std::pairs. Keep in mind though that if there are repeated keys in your input, only the first one will be inserted to the map (if you use multimap everything will be inserted of course):

#include <boost/fusion/include/std_pair.hpp>
...
qi::rule<std::string::const_iterator, std::pair<double,int>()> pair_rule = 
    qi::double_ >> qi::lit('=') >> qi::int_;
qi::rule<std::string::const_iterator, std::map<double,int>()> rule = 
    pair_rule%qi::lit(',');
//You can also use
//qi::rule<std::string::const_iterator, std::map<double,int>()> rule =
    //(qi::double_ >> qi::lit('=') >> qi::int_)%qi::lit(',');

您自己的结构作为一个容器结果
用精神的定制点你也可以让你的结构的行为好象它使用属性打交道时是一个容器。你需要专门的最低为 is_container container_value push_back_container 。这里有几个例子:

Your own struct as a container
Using spirit's customization points you can also make your struct behave as if it were a container when dealing with attributes. The minimum you need to specialize are is_container, container_value and push_back_container. Here are a couple of examples:

第一个是相当简单的(和愚蠢的)。它使你的结构与兼容属性的std ::矢量&lt;&INT GT; 。每一个int解析它的时间将被添加到累加器总量。你可以找到少傻办法<一href=\"http://stackoverflow.com/questions/17042851/boost-spirit-parse-integer-to-custom-list-template/17044748#17044748\">here和<一个href=\"http://stackoverflow.com/questions/12520649/pass-attribute-to-child-rule-in-boost-spirit/12527010#12527010\">here (在老答案)。

The first one is rather simple (and silly). It makes your struct have an attribute compatible with std::vector<int>. Every time an int is parsed it is added to the total in the accumulator. You can find less silly approaches here and here (in the "old answer").

struct accumulator
{
    accumulator(): total(){}
    int total;
};

namespace boost{ namespace spirit{ namespace traits
{
    template<>
    struct is_container<accumulator> : boost::mpl::true_
    {};

    template<>
    struct container_value<accumulator>
    {
        typedef int type;
    };

    template<>
    struct push_back_container<accumulator,int>
    {
        static bool call(accumulator& c, int val)
        {
            c.total+=val;
            return true;
        }
    };
}}}
...
qi::rule<Iterator,accumulator()> rule =
    qi::int_%qi::lit(',');


第二个是稍微复杂一点(不要太多)。它使你的结构与 STD兼容属性::矢量&lt;提高::变体LT; INT,标准::字符串&GT; &GT; 。当一个int解析它被添加到整数容器中的分销商,类似的字符串存储在字符串容器。使用这样的例子( 1 2 和<一个href=\"http://boost.2283326.n4.nabble.com/Omitting-unused-type-inside-Kleene-Star-td4643647.html\">3).


The second one is a little more complex (not much). It makes your struct have an attribute compatible with std::vector<boost::variant<int,std::string> >. When an int is parsed it is added to the ints container in the distributor, similarly strings are stored in the strings container. Examples using this (1, 2 and 3).

struct distributor
{
    distributor():ints(),strings(){}
    std::vector<int> ints;
    std::vector<std::string> strings;
};

namespace boost{ namespace spirit{ namespace traits
{
    template<>
    struct is_container<distributor> : boost::mpl::true_
    {};

    template<>
    struct container_value<distributor>
    {
        typedef boost::variant<int,std::string> type;
    };

    template<>
    struct push_back_container<distributor,int>
    {
        static bool call(distributor& c, int val)
        {
            c.ints.push_back(val);
            return true;
        }
    };

    template<>
    struct push_back_container<distributor,std::string>
    {
        static bool call(distributor& c, std::string const& val)
        {
            c.strings.push_back(val);
            return true;
        }
    };
}}}
...
qi::rule<std::string::const_iterator, std::string()> string_rule = 
    +~qi::char_(',');
qi::rule<std::string::const_iterator, distributor()> rule = 
    (qi::int_ | string_rule)%qi::lit(',');


在一个cpp文件所有的测试

#include <iostream>
#include <string>
#include <utility>
#include <tuple>
#include <list>
#include <vector>
#include <map>

#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/std_tuple.hpp> 

#include <boost/spirit/include/qi.hpp>

#include <boost/variant.hpp>

namespace qi=boost::spirit::qi;

struct normal_struct
{
    int integer;
    double real;
};

struct struct_with_single_element_container
{
    std::vector<int> cont;
};

BOOST_FUSION_ADAPT_STRUCT(
    normal_struct,
    (int, integer)
    (double, real)
)

BOOST_FUSION_ADAPT_STRUCT(
    struct_with_single_element_container,
    (std::vector<int>, cont)
)

struct accumulator
{
    accumulator(): total(){}
    int total;
};

namespace boost{ namespace spirit{ namespace traits
{
    template<>
    struct is_container<accumulator> : boost::mpl::true_
    {};

    template<>
    struct container_value<accumulator>
    {
        typedef int type;
    };

    template<>
    struct push_back_container<accumulator,int>
    {
        static bool call(accumulator& c, int val)
        {
            c.total+=val;
            return true;
        }
    };
}}}

struct distributor
{
    distributor():ints(),strings(){}
    std::vector<int> ints;
    std::vector<std::string> strings;
};

namespace boost{ namespace spirit{ namespace traits
{
    template<>
    struct is_container<distributor> : boost::mpl::true_
    {};

    template<>
    struct container_value<distributor>
    {
        typedef boost::variant<int,std::string> type;
    };

    template<>
    struct push_back_container<distributor,int>
    {
        static bool call(distributor& c, int val)
        {
            c.ints.push_back(val);
            return true;
        }
    };

    template<>
    struct push_back_container<distributor,std::string>
    {
        static bool call(distributor& c, std::string const& val)
        {
            c.strings.push_back(val);
            return true;
        }
    };
}}}


int main()
{
    {
        std::pair<int,double> parsed;
        qi::rule<std::string::const_iterator, std::pair<int,double>()> rule = 
                    qi::int_ >> qi::lit(',') >> qi::double_;
        std::string test="1,2.5";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "First: " << parsed.first << ", Second: " << parsed.second << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

    {
        std::tuple<int,std::string,double> parsed;
        qi::rule<std::string::const_iterator, std::tuple<int,std::string,double>()> rule = 
                    qi::int_ >> qi::lit(',') >> +~qi::char_(',') >> qi::lit(',') >> qi::double_;
        std::string test="1,abc,2.5";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "get<0>: " << std::get<0>(parsed) << ", get<1>: " << std::get<1>(parsed) << ", get<2>: " << std::get<2>(parsed) << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

    {
        normal_struct parsed;
        qi::rule<std::string::const_iterator, normal_struct()> rule = 
                    qi::int_ >> qi::lit(',') >> qi::double_;
        std::string test="1,2.5";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "integer: " << parsed.integer << ", real: " << parsed.real << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

    {
        struct_with_single_element_container parsed;
        //there is a problem when you have a struct with a single element container, the workaround is simply adding qi::eps to the rule
        qi::rule<std::string::const_iterator, struct_with_single_element_container()> rule = 
                    qi::eps >> qi::int_%qi::lit(','); 
        std::string test="1,2";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "[0]: " << parsed.cont[0] << ", [1]: " << parsed.cont[1] << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

    {
        std::list<int> parsed;
        qi::rule<std::string::const_iterator, std::list<int>()> rule = 
                    qi::int_%qi::lit(',');
        std::string test="1,2";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "front: " << parsed.front() << ", back: " << parsed.back() << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

    {
        std::map<double,int> parsed;
        qi::rule<std::string::const_iterator, std::pair<double,int>()> pair_rule = 
                    qi::double_ >> qi::lit('=') >> qi::int_;
        qi::rule<std::string::const_iterator, std::map<double,int>()> rule = 
                    pair_rule%qi::lit(',');
        std::string test="2.5=1,3.5=2";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "map[2.5]: " << parsed[2.5] << ", map[3.5]: " << parsed[3.5] << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

    {
        accumulator parsed;
        qi::rule<std::string::const_iterator, accumulator()> rule = 
                    qi::int_%qi::lit(',');
        std::string test="1,2,3";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "total: " << parsed.total << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

    {
        distributor parsed;
        qi::rule<std::string::const_iterator, std::string()> string_rule = 
                    +~qi::char_(',');
        qi::rule<std::string::const_iterator, distributor()> rule = 
                    (qi::int_ | string_rule)%qi::lit(',');
        std::string test="abc,1,2,def,ghi,3,jkl";
        std::string::const_iterator iter=test.begin(), end=test.end();
        bool result = qi::parse(iter,end,rule,parsed);
        if(result && iter==end)
        {
            std::cout << "Success." << std::endl;
            std::cout << "ints" << std::endl;
            for(auto val: parsed.ints)
                std::cout << val << std::endl;
            std::cout << "strings" << std::endl;
            for(const auto& val: parsed.strings)
                std::cout << val << std::endl;
        }
        else
        {
            std::cout << "Failure." << std::endl;
            std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
        }
    }

}

这篇关于获取的boost ::精神::气使用STL容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆