从灵气中制作共享指针的向量
making a vector of shared pointers from Spirit Qi
这是 的后续问题。
我可以从语法中解析为字符串向量,但我似乎无法解析为指向字符串的共享指针的向量;即 std::vector<std::shared_ptr<std::string> >
,需要一点帮助。
我的编译头文件:
#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
// this solution for lazy make shared comes from the SO forum, user sehe.
//
// post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
template <typename T>
struct make_shared_f
{
template <typename... A> struct result
{ typedef std::shared_ptr<T> type; };
template <typename... A>
typename result<A...>::type operator()(A&&... a) const {
return std::make_shared<T>(std::forward<A>(a)...);
}
};
template <typename T>
using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template<typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper>
{
SystemParser() : SystemParser::base_type(variable_group_)
{
namespace phx = boost::phoenix;
using qi::_1;
using qi::_val;
using qi::eps;
using qi::lit;
var_counter = 0;
declarative_symbols.add("variable_group",0);
variable_group_ = "variable_group" > genericvargp_ > ';';
genericvargp_ = new_variable_ % ','; //
new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>() (_1)];
unencountered_symbol_ = valid_variable_name_ - ( encountered_variables | declarative_symbols );
valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_") );
// debug(variable_group_); debug(unencountered_symbol_); debug(new_variable_); debug(genericvargp_);
// BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
}
// rule declarations. these are member variables for the parser.
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > variable_group_;
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > genericvargp_;
qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_;
qi::rule<Iterator, std::string()> unencountered_symbol_;
qi::rule<Iterator, std::string()> valid_variable_name_;
unsigned var_counter;
qi::symbols<char,int> encountered_variables;
qi::symbols<char,int> declarative_symbols;
};
驱动程序代码:
int main(int argc, char** argv)
{
std::vector<std::shared_ptr<std::string> > V;
std::string str = "variable_group x, y, z; ";
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
SystemParser<std::string::const_iterator> S;
bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);
if (s)
{
std::cout << "Parse succeeded: " << V.size() << " variables\n";
for (auto& s : V)
std::cout << " - '" << s << "'\n";
}
else
std::cout << "Parse failed\n";
if (iter!=end)
std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
return 0;
}
文本被正确解析,但生成的向量长度为 0,而它的长度应为 3。不知何故,std::shared_ptr<string>
没有被推到由规则 genericvargp_
。
我已经尝试了很多东西,包括从测试解析中读取所有调试信息,以及放置规则定义的 %=
符号,这些规则应该用于有语义操作的规则除非我弄错了,否则不会分配 _val
。我也玩了一整天,用 phx::bind
手动推到 _val
的后面,但一无所获。我进一步验证了sehe在另一个答案中提供的make_shared_
实际上是懒惰的std::shared_ptr。
顺便说一句,我也一直在努力将 unencountered_symbol_
的结果添加到 encountered_variables
以强制变量名称的唯一性...
问题似乎是将 new_variable_
规则的结果传播到 genericvargp_
规则中所需的共享指针向量。
这个声明
qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_;
与所需类型不匹配:
qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;
遗憾的是,在旧的 SpiritV2 中,这个属性被默默地忽略了,并且没有进行属性传播。这也解释了为什么它没有在编译时出错。
#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#define BOOST_SPIRIT_DEBUG 1
#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
// this solution for lazy make shared comes from the SO forum, user sehe.
//
// post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
template <typename T> struct make_shared_f {
template <typename... A> struct result { typedef std::shared_ptr<T> type; };
template <typename... A> typename result<A...>::type operator()(A &&... a) const {
return std::make_shared<T>(std::forward<A>(a)...);
}
};
template <typename T> using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> {
SystemParser() : SystemParser::base_type(variable_group_) {
namespace phx = boost::phoenix;
using qi::_1;
using qi::_val;
using qi::eps;
using qi::lit;
var_counter = 0;
declarative_symbols.add("variable_group", 0);
variable_group_ = "variable_group" > genericvargp_ > ';';
genericvargp_ = new_variable_ % ','; //
new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>()(_1)];
unencountered_symbol_ = valid_variable_name_ - (encountered_variables | declarative_symbols);
valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_"));
BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
}
// rule declarations. these are member variables for the parser.
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> variable_group_;
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> genericvargp_;
qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;
qi::rule<Iterator, std::string()> unencountered_symbol_;
qi::rule<Iterator, std::string()> valid_variable_name_;
unsigned var_counter;
qi::symbols<char, qi::unused_type> encountered_variables;
qi::symbols<char, qi::unused_type> declarative_symbols;
};
int main()
{
std::vector<std::shared_ptr<std::string> > V;
std::string str = "variable_group x, y, z; ";
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
SystemParser<std::string::const_iterator> S;
bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);
if (s)
{
std::cout << "Parse succeeded: " << V.size() << " variables\n";
for (auto& s : V)
std::cout << " - '" << *s << "'\n";
}
else
std::cout << "Parse failed\n";
if (iter!=end)
std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}
版画
Parse succeeded: 3 variables
- 'x'
- 'y'
- 'z'
还有很多调试信息
这是
我可以从语法中解析为字符串向量,但我似乎无法解析为指向字符串的共享指针的向量;即 std::vector<std::shared_ptr<std::string> >
,需要一点帮助。
我的编译头文件:
#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
// this solution for lazy make shared comes from the SO forum, user sehe.
//
// post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
template <typename T>
struct make_shared_f
{
template <typename... A> struct result
{ typedef std::shared_ptr<T> type; };
template <typename... A>
typename result<A...>::type operator()(A&&... a) const {
return std::make_shared<T>(std::forward<A>(a)...);
}
};
template <typename T>
using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template<typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper>
{
SystemParser() : SystemParser::base_type(variable_group_)
{
namespace phx = boost::phoenix;
using qi::_1;
using qi::_val;
using qi::eps;
using qi::lit;
var_counter = 0;
declarative_symbols.add("variable_group",0);
variable_group_ = "variable_group" > genericvargp_ > ';';
genericvargp_ = new_variable_ % ','; //
new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>() (_1)];
unencountered_symbol_ = valid_variable_name_ - ( encountered_variables | declarative_symbols );
valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_") );
// debug(variable_group_); debug(unencountered_symbol_); debug(new_variable_); debug(genericvargp_);
// BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
}
// rule declarations. these are member variables for the parser.
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > variable_group_;
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > genericvargp_;
qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_;
qi::rule<Iterator, std::string()> unencountered_symbol_;
qi::rule<Iterator, std::string()> valid_variable_name_;
unsigned var_counter;
qi::symbols<char,int> encountered_variables;
qi::symbols<char,int> declarative_symbols;
};
驱动程序代码:
int main(int argc, char** argv)
{
std::vector<std::shared_ptr<std::string> > V;
std::string str = "variable_group x, y, z; ";
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
SystemParser<std::string::const_iterator> S;
bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);
if (s)
{
std::cout << "Parse succeeded: " << V.size() << " variables\n";
for (auto& s : V)
std::cout << " - '" << s << "'\n";
}
else
std::cout << "Parse failed\n";
if (iter!=end)
std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
return 0;
}
文本被正确解析,但生成的向量长度为 0,而它的长度应为 3。不知何故,std::shared_ptr<string>
没有被推到由规则 genericvargp_
。
我已经尝试了很多东西,包括从测试解析中读取所有调试信息,以及放置规则定义的 %=
符号,这些规则应该用于有语义操作的规则除非我弄错了,否则不会分配 _val
。我也玩了一整天,用 phx::bind
手动推到 _val
的后面,但一无所获。我进一步验证了sehe在另一个答案中提供的make_shared_
实际上是懒惰的std::shared_ptr。
顺便说一句,我也一直在努力将 unencountered_symbol_
的结果添加到 encountered_variables
以强制变量名称的唯一性...
问题似乎是将 new_variable_
规则的结果传播到 genericvargp_
规则中所需的共享指针向量。
这个声明
qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_;
与所需类型不匹配:
qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;
遗憾的是,在旧的 SpiritV2 中,这个属性被默默地忽略了,并且没有进行属性传播。这也解释了为什么它没有在编译时出错。
#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#define BOOST_SPIRIT_DEBUG 1
#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
// this solution for lazy make shared comes from the SO forum, user sehe.
//
// post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
template <typename T> struct make_shared_f {
template <typename... A> struct result { typedef std::shared_ptr<T> type; };
template <typename... A> typename result<A...>::type operator()(A &&... a) const {
return std::make_shared<T>(std::forward<A>(a)...);
}
};
template <typename T> using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> {
SystemParser() : SystemParser::base_type(variable_group_) {
namespace phx = boost::phoenix;
using qi::_1;
using qi::_val;
using qi::eps;
using qi::lit;
var_counter = 0;
declarative_symbols.add("variable_group", 0);
variable_group_ = "variable_group" > genericvargp_ > ';';
genericvargp_ = new_variable_ % ','; //
new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>()(_1)];
unencountered_symbol_ = valid_variable_name_ - (encountered_variables | declarative_symbols);
valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_"));
BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
}
// rule declarations. these are member variables for the parser.
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> variable_group_;
qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> genericvargp_;
qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;
qi::rule<Iterator, std::string()> unencountered_symbol_;
qi::rule<Iterator, std::string()> valid_variable_name_;
unsigned var_counter;
qi::symbols<char, qi::unused_type> encountered_variables;
qi::symbols<char, qi::unused_type> declarative_symbols;
};
int main()
{
std::vector<std::shared_ptr<std::string> > V;
std::string str = "variable_group x, y, z; ";
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
SystemParser<std::string::const_iterator> S;
bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);
if (s)
{
std::cout << "Parse succeeded: " << V.size() << " variables\n";
for (auto& s : V)
std::cout << " - '" << *s << "'\n";
}
else
std::cout << "Parse failed\n";
if (iter!=end)
std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}
版画
Parse succeeded: 3 variables
- 'x'
- 'y'
- 'z'
还有很多调试信息