我一直致力于对编译时代码有更好的理解,特别是在灵性::X3方面。我有一个类my_uuid,它使用x3::rule编译得很好。但是,由于Iterator被声明在范围之外,所以它只对std::string::iterator有好处。所以我想我应该创建一个像x3::int_parser这样的组件。据我所见,它有着完全相同的签名。我试着把它放在x3命名空间中,并在`..\x3\numeric\int.hpp的标题后面包含,认为有一些很好的理由,但它回避了我。
如果我在我的uuid_parser和int_parser中设置了一个断点,我可以看到int_parser是单独的,从解析器序列中被调用。但是我的解析器被包装得好像它是一个容器。如果我在第40行取消解析器的注释,编译器就会开始查找像insert这样的解析器。所以,这就更令人困惑了,如果我把它作为序列中的最后一个组件,为什么它不按照insert或move的需要编译呢?
我好像错过了一些最基本的东西。我的问题不是如何解决这个问题,而是我错过了什么。谢谢。
#include<iostream>
#include <vector>
#include <boost/spirit/home/x3.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
namespace x3 = boost::spirit::x3;
struct uuid_parser : x3::parser<uuid_parser> {
typedef boost::uuids::uuid attribute_type;
static bool const has_attribute = true;
static bool const handles_container = false;
template <typename Iterator, typename Context, typename Attribute>
bool parse(Iterator& first, Iterator const& last, Context const& context, x3::unused_type, Attribute& uuid) const {
boost::iterator_range<Iterator> rng;
auto ret = x3::parse(first, last, x3::raw[*x3::char_("0-9a-fA-F-")], rng);
try {
uuid = boost::uuids::string_generator()(rng.begin(), rng.end());
}
catch (std::exception& e) {
boost::ignore_unused(e);
return false;
}
return true;
}
};
const uuid_parser uuid_ = {};
int main() {
std::string uuid_str(R"( id(78461bab-6d7c-48bc-a79a-b716d1ab97cb
id(9350cf32-7fe5-40d2-8a0d-c7f7562d7a15
id(bad-9350cf32-7fe5-40d2-8a0d-c7f7562d7a15
)");
auto first(uuid_str.begin());
std::vector<boost::uuids::uuid> attr;
x3::phrase_parse(first, uuid_str.end(), *(x3::lit("id(") >> uuid_), x3::space, attr);
//x3::phrase_parse(first, uuid_str.end(), *(x3::lit("uid(") >> uuid_ >> ')'), x3::space, attr);
for (auto& item : attr)
std::cout << item << std::endl;
std::string int_str(" x(1) x(2) x(3)"); auto ibegin(int_str.begin());
std::vector<int> int_vect;
x3::phrase_parse(ibegin, int_str.end(), *(x3::lit("x(") >> x3::int_ >> ')'), x3::space, int_vect);
for (auto& item : int_vect)
std::cout << item << std::endl;
return 0;
}发布于 2022-02-08 20:37:00
令人困惑的是,uuids::uuid看起来像一个容器。您可以通过添加:
template <> struct x3::traits::detail::is_container_impl<boost::uuids::uuid> {
using type = std::false_type;
};住在Coliru
#include <iostream>
#include <vector>
#include <boost/spirit/home/x3.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
namespace x3 = boost::spirit::x3;
struct uuid_parser : x3::parser<uuid_parser> {
using attribute_type = boost::uuids::uuid;
static bool const has_attribute = true;
static bool const handles_container = false;
template <typename Iterator, typename Context, typename Attribute>
bool parse(Iterator& first, Iterator const& last, Context const& context,
x3::unused_type, Attribute& uuid) const
{
try {
boost::iterator_range<Iterator> rng;
auto ret = x3::parse(first, last, x3::raw[*(x3::xdigit | '-')], rng);
if (ret)
uuid = boost::uuids::string_generator()(rng.begin(), rng.end());
return true;
} catch (std::exception const&) {
return false;
}
}
};
template <> struct x3::traits::detail::is_container_impl<boost::uuids::uuid> {
using type = std::false_type;
};
int main() {
const uuid_parser uuid_ = {};
std::string uuid_str(R"( uid(78461bab-6d7c-48bc-a79a-b716d1ab97cb)
uid(9350cf32-7fe5-40d2-8a0d-c7f7562d7a15)
uid(bad-9350cf32-7fe5-40d2-8a0d-c7f7562d7a15)
)");
std::vector<boost::uuids::uuid> vec;
x3::phrase_parse(uuid_str.begin(), uuid_str.end(), *("uid(" >> uuid_ >> ")"), x3::space, vec);
for (auto const& item : vec)
std::cout << item << std::endl;
}打印
78461bab-6d7c-48bc-a79a-b716d1ab97cb
9350cf32-7fe5-40d2-8a0d-c7f7562d7a15增加一些可调性
住在Coliru
auto u = x3::rule<struct _u, boost::uuids::uuid>{"u"} = uuid_;
auto r = x3::rule<struct _r, boost::uuids::uuid>{"r"} = "uid(" >> u >> ")";
x3::phrase_parse(uuid_str.begin(), uuid_str.end(), *r, x3::space, vec);打印
<r>
<try> uid(78461bab-6d7</try>
<u>
<try>78461bab-6d7c-48bc-a</try>
<success>)\n uid(9350cf</success>
<attributes>78461bab-6d7c-48bc-a79a-b716d1ab97cb</attributes>
</u>
<success>\n uid(9350cf3</success>
<attributes>78461bab-6d7c-48bc-a79a-b716d1ab97cb</attributes>
</r>
<r>
<try>\n uid(9350cf3</try>
<u>
<try>9350cf32-7fe5-40d2-8</try>
<success>)\n uid(bad-93</success>
<attributes>9350cf32-7fe5-40d2-8a0d-c7f7562d7a15</attributes>
</u>
<success>\n uid(bad-935</success>
<attributes>9350cf32-7fe5-40d2-8a0d-c7f7562d7a15</attributes>
</r>
<r>
<try>\n uid(bad-935</try>
<u>
<try>bad-9350cf32-7fe5-40</try>
<fail/>
</u>
<fail/>
</r>
78461bab-6d7c-48bc-a79a-b716d1ab97cb
9350cf32-7fe5-40d2-8a0d-c7f7562d7a15简化
实际上,正如您所看到的,不需要来使用BOOST_SPIRIT_DEFINE,完全将实例化和声明分离开来:
住在Coliru
#include <iostream>
#include <vector>
#include <boost/spirit/home/x3.hpp>
#include <boost/lexical_cast/try_lexical_convert.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
namespace x3 = boost::spirit::x3;
template <> struct x3::traits::detail::is_container_impl<boost::uuids::uuid> {
using type = std::false_type;
};
namespace Parser {
template <typename T> static inline auto as(auto p) {
return x3::rule<struct _, T>{"as"} = p;
}
static inline auto const to_uuid = [](auto& ctx) {
auto r = _attr(ctx);
_pass(ctx) = boost::conversion::try_lexical_convert<boost::uuids::uuid>(
std::string_view{r.begin(), r.end()}, _val(ctx));
};
static inline auto const uuid_ =
as<boost::uuids::uuid>(x3::raw[*(x3::xdigit | '-')][to_uuid]);
} // namespace Parser
int main() {
std::string uuid_str(R"( uid(78461bab-6d7c-48bc-a79a-b716d1ab97cb)
uid(9350cf32-7fe5-40d2-8a0d-c7f7562d7a15)
uid(bad-9350cf32-7fe5-40d2-8a0d-c7f7562d7a15)
)");
std::vector<boost::uuids::uuid> vec;
x3::phrase_parse(uuid_str.begin(), uuid_str.end(), *("uid(" >> Parser::uuid_ >> ")"), x3::space, vec);
for (auto const& item : vec)
std::cout << item << std::endl;
}打印
78461bab-6d7c-48bc-a79a-b716d1ab97cb
9350cf32-7fe5-40d2-8a0d-c7f7562d7a15另外,除了..。
你说“爱尔兰人”是硬编码的。事实上,是的。但是要知道,这只用于显式模板专门化。没有什么可以阻止您专门为几个迭代器类型!
参见例如您可以通过制造一个正确的上下文类型并实例化(以及)来解决这个问题。
https://stackoverflow.com/questions/71022141
复制相似问题