我试着用parse解析一些东西,精灵的气库,我遇到了一个问题。根据精神医生,a >> b应该生成tuple<A, B>类型的东西。但是这是一个boost::tuple (也就是融合向量),而不是std::tuple (我想要)。
有什么简单的方法可以在boost::tuple std::tuple**?** => std::tuple**?**之间进行这种转换吗?
同一文档页指出,*a应该生成类型为vector<A>的东西。这似乎产生了一个std::vector<A> (或者某种可以隐式转换为std::vector<A>的boost::vector<A> )。我只想知道这种行为是否适用于元组。
发布于 2013-08-10 05:03:00
简短答覆:
使用#include <boost/fusion/adapted/std_tuple.hpp>。
更完整的答案:
如您所见,这里
在属性表中,我们将只使用
vector<A>和tuple<A, B...>作为占位符。vector<A>的表示法代表任何包含A类型的STL容器元素,tuple<A, B...>表示任何Boost.Fusion序列保持A、B、.等要素。最后,未使用的表示unused_type。
因此,当解析器/生成器有一个属性为tuple<A,B...>时,您可以使用任何融合序列(例如融合::向量或融合::list)或任何可以适应融合序列的内容(例如boost::数组、boost::tuple、std::结对、std::tuple、std::tuple,您自己使用BOOST_FUSION_ADAPT_STRUCT的结构)。
当它有vector<A>时,如果您的元素是对的,可以使用std::vector<A>、std::list,甚至std::map。如果您还专门化了几个定制点,也可以使用自己的结构(至少在boost::container_value和push_back_container中是这样的)。
std::对
为了能够将std::pair与spirit一起使用,只需添加一个标题:
#include <boost/fusion/include/std_pair.hpp>
...
qi::rule<Iterator,std::pair<int,double>()> rule =
qi::int_ >> qi::lit(',') >> qi::double_;std::tuple
从boost 1.48.0开始,您可以对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的帮助下,您可以很容易地调整您的自定义结构:
#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_;但是,有一个已知的限制,当您尝试使用具有单个元素(也是容器编译)的结构时,除非将qi::eps >> ...添加到您的规则中,否则会失败。
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::map
您可以简单地使用std::map作为std::对的容器。不过,请记住,如果输入中有重复的键,则只有第一个键将被插入到映射中(当然,如果使用multimap,所有内容都将被插入):
#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。以下是几个例子:
第一个很简单(而且很傻)。它使您的结构具有一个与std::vector<int>兼容的属性。每次解析int时,它都被添加到累加器中的总数中。您可以找到不那么愚蠢的方法这里和这里 (在“旧答案”中)。
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::vector<boost::variant<int,std::string> >兼容的属性。当一个int被解析时,它将被添加到分发服务器中的ints容器中,类似地,字符串也存储在strings容器中。使用此示例(1、2和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;
}
}
}https://stackoverflow.com/questions/18158376
复制相似问题