为什么我的组件编译为容器但 spirit::x3::int_parser 没有?
Why does my component compile as a container but spirit::x3::int_parser does not?
我一直致力于更好地理解编译时代码,尤其是 spirit::x3。我有一个 class my_uuid
,用 x3::rule 编译它工作正常。但是由于 Iterator
是在范围之外声明的,所以它只适用于 std::string::iterator
。所以我想我只是创建一个像 x3::int_parser
这样写的组件。据我所知,它具有完全相同的签名。我试过将它放在 x3
命名空间中,并在 `..\x3\numeric\int.hpp' header 之后包含它,我认为这是有充分理由的,但它让我望而却步。
如果我在我的 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;
}
令人困惑的是 uuids::uuid
看起来像一个容器。您可以通过添加以下内容来观察这一点:
template <> struct x3::traits::detail::is_container_impl<boost::uuids::uuid> {
using type = std::false_type;
};
Live On 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
添加一些可调试性
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
,完全将实例化与声明分开:
#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
此外,此外...
你说“迭代器”是硬编码的。事实上,它是。但请注意,这仅用于显式模板专业化。没有什么能阻止您专注于多种迭代器类型!
参见例如
我一直致力于更好地理解编译时代码,尤其是 spirit::x3。我有一个 class my_uuid
,用 x3::rule 编译它工作正常。但是由于 Iterator
是在范围之外声明的,所以它只适用于 std::string::iterator
。所以我想我只是创建一个像 x3::int_parser
这样写的组件。据我所知,它具有完全相同的签名。我试过将它放在 x3
命名空间中,并在 `..\x3\numeric\int.hpp' header 之后包含它,我认为这是有充分理由的,但它让我望而却步。
如果我在我的 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;
}
令人困惑的是 uuids::uuid
看起来像一个容器。您可以通过添加以下内容来观察这一点:
template <> struct x3::traits::detail::is_container_impl<boost::uuids::uuid> {
using type = std::false_type;
};
Live On 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
添加一些可调试性
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
,完全将实例化与声明分开:
#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
此外,此外...
你说“迭代器”是硬编码的。事实上,它是。但请注意,这仅用于显式模板专业化。没有什么能阻止您专注于多种迭代器类型!
参见例如