gpt4 book ai didi

c++ - 无法从 Boost.Spirit 中的占位符构造 std::string

转载 作者:行者123 更新时间:2023-11-28 02:04:13 24 4
gpt4 key购买 nike

我已经开始研究基于 Boost.Spirit 的简单解析器,它将解析类似 C++ 的文件(唯一类似 C++ 的部分是内置模板类型;例如 map<string, smart_ptr<int>> name_object_map; - 但这是内置的编译器,用户不能声明模板类)。尽管如此,语法旨在包含数据结构声明,而不是表达式,除了用于枚举器声明初始化的常量表达式; enum E { a = 4 * 5 + 3 };已验证。这对我来说目前不是问题,因为我无法解析 E我想要的方式:)

我昨天在阅读文档和示例后做了以下内容,但它没有编译:

#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_char_class.hpp>
#include <cassert>
#include <memory>
#include <string>
#include <utility>

struct context {};

class foo {
std::string name;
const context *ctx;

public:
foo(const std::string &name, const context *ctx) : name(name), ctx(ctx) {}
};

using foo_ref = std::shared_ptr<foo>;

template <typename Iterator>
struct skipper : boost::spirit::qi::grammar<Iterator> {
skipper() : skipper::base_type(start) {
using namespace boost::spirit;
qi::char_type char_;
ascii::space_type space;

start = space // tab/space/cr/lf
| "/*" >> *(char_ - "*/") >> "*/" // C-style comments
;
}

boost::spirit::qi::rule<Iterator> start;
};

template <typename Iterator>
struct the_parser : boost::spirit::qi::grammar<Iterator, std::vector<foo_ref>(),
skipper<Iterator>> {
the_parser() : the_parser::base_type(start), current_context(&root) {
using namespace boost::spirit;
namespace phx = boost::phoenix;

identifier = qi::lexeme[qi::alpha >> *qi::alnum];
start = *(foo_decl); // currently, no semantic action attached.
// This will create the root decl in ast.

foo_decl = (lit("foo") >> identifier)[qi::_val = std::make_shared<foo>(
qi::_1, current_context)] >>
qi::char_('{') >> qi::char_('}') >> qi::char_(';');
BOOST_SPIRIT_DEBUG_NODES((identifier)(start)(foo_decl));
}
boost::spirit::qi::rule<Iterator, std::string(), skipper<Iterator>>
identifier;
boost::spirit::qi::rule<Iterator, std::vector<foo_ref>(), skipper<Iterator>>
start;
boost::spirit::qi::rule<Iterator, foo_ref(), skipper<Iterator>> foo_decl;
context root;
const context *current_context;
};

int main() {
the_parser<std::string::const_iterator> parser;
std::vector<foo_ref> root;

const std::string content = "foo john_doe { };";
auto first = content.cbegin(), last = content.cend();
bool r = boost::spirit::qi::phrase_parse(
first, last, parser, skipper<std::string::const_iterator>(), root);
assert(r && first == last);
}

在 Mac 上用 clang 编译(第一行是 std::make_shared ):

error: no matching constructor for initialization of 'foo'
__second_(_VSTD::forward<_Args2>(_VSTD::get<_I2>(__second_args))...)
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
note: candidate constructor not viable: no known conversion from 'const boost::phoenix::actor<boost::spirit::argument<0> >' to 'const std::string' (aka
'const basic_string<char, char_traits<char>, allocator<char> >') for 1st argument
foo(const std::string &name, const context *ctx) : name(name), ctx(ctx) {}
^

foo_decl s 语义 Action ,它不能构造一个 foo (通过 std::make_shared ),因为第一个属性的结果无法转换为 std::string .但是,如果我添加一个类成员 std::string s ,并改为执行此操作,它有效:

foo_decl = (lit("foo") >> identifier)[boost::phoenix::ref(s) = qi::_1] >>
qi::char_('{') >> qi::char_('}') >> qi::char_(';');

同样,如果我尝试 std::cout它,我可以看到john_doe打印出来。

如果我用 phoenix 绑定(bind)一个成员函数调用,它也有效:

foo_decl = (lit("foo") >> identifier)[qi::_val =
boost::phoenix::bind(&the_parser, this, qi::_1)] >>
qi::char_('{') >> qi::char_('}') >> qi::char_(';');

foo_ref make_foo(const std::string &n) {
return std::make_shared(n, current_context);
}

这最后三个解决方法意味着有一个来自 decltype(qi::_1) 的隐式转换序列至 std::string ;这不对吗?

如果您能指出我的错误或我对语义操作和占位符工作原理的理解上的差距,我将非常高兴。为什么std::make_shared我觉得很奇怪不起作用。

谢谢!

最佳答案

首先:

使用第一个链接中的 phoenix::function:

Live On Coliru

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <cassert>
#include <memory>
#include <string>
#include <utility>

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> >;
}

struct context {};

class foo {
std::string name;
const context *ctx;

public:
foo(const std::string &name, const context *ctx) : name(name), ctx(ctx) {}
};

using foo_ref = std::shared_ptr<foo>;

template <typename Iterator> struct skipper : boost::spirit::qi::grammar<Iterator> {
skipper() : skipper::base_type(start) {
using namespace boost::spirit;
qi::char_type char_;
ascii::space_type space;

start = space // tab/space/cr/lf
| "/*" >> *(char_ - "*/") >> "*/" // C-style comments
;
}

boost::spirit::qi::rule<Iterator> start;
};

template <typename Iterator>
struct the_parser : boost::spirit::qi::grammar<Iterator, std::vector<foo_ref>(), skipper<Iterator> > {
the_parser() : the_parser::base_type(start), current_context(&root) {
using namespace boost::spirit;
namespace phx = boost::phoenix;

identifier = qi::alpha >> *qi::alnum;
// This will create the root decl in ast.

foo_decl = ("foo" >> identifier) [qi::_val = make_shared_<foo>{}(qi::_1, current_context)] >>
'{' >> '}' >> ';';

start = *foo_decl; // currently, no semantic action attached.
BOOST_SPIRIT_DEBUG_NODES((identifier)(start)(foo_decl));
}
boost::spirit::qi::rule<Iterator, std::string()> identifier;
boost::spirit::qi::rule<Iterator, foo_ref(), skipper<Iterator> > foo_decl;
boost::spirit::qi::rule<Iterator, std::vector<foo_ref>(), skipper<Iterator> > start;
context root;
const context *current_context;
};

int main() {
the_parser<std::string::const_iterator> parser;
std::vector<foo_ref> root;

const std::string content = "foo johndoe { };";
auto first = content.cbegin(), last = content.cend();
bool r = boost::spirit::qi::phrase_parse(first, last, parser, skipper<std::string::const_iterator>(), root);
if (r)
std::cout << "success\n";
else
std::cout << "failed\n";

if (first != last)
std::cout << "remaining unparsed: '" << std::string(first,last) << "'\n";

}

打印

success

连同

的调试输出
<start>
<try>foo johndoe { };</try>
<foo_decl>
<try>foo johndoe { };</try>
<identifier>
<try>johndoe { };</try>
<success> { };</success>
<attributes>[[j, o, h, n, d, o, e]]</attributes>
</identifier>
<success></success>
<attributes>[0x60600000ebb0]</attributes>
</foo_decl>
<foo_decl>
<try></try>
<fail/>
</foo_decl>
<success></success>
<attributes>[[0x60600000ebb0]]</attributes>
</start>

关于c++ - 无法从 Boost.Spirit 中的占位符构造 std::string,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38221690/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com