c++ - 将 Boost Spirit 解析器从 boost::variant 转换为 std::variant 2
问题描述
我正在尝试使用 x3 解析器std::variant
代替boost::variant
,但没有成功。
我关注了关于这个主题的帖子:从 boost::variant 到 std::variant 的转换提升精神解析器,但在我的情况下,让它工作所需的样板似乎不起作用。(简化的)错误消息指出:
std::variant<...> has no member named apply_visitor
我承认,但这个样板对我来说是如此的不明飞行物,我将无法修复它。
这是重现我的问题的最小测试代码,可在 coliru 上找到:
#include <iostream>
#include <variant>
#define BOOST_SPIRIT_X3_DEBUG
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
// boiler plate provided in the original post
namespace boost::spirit::x3::traits {
template<typename... T>
struct is_variant<std::variant<T...> >
: mpl::true_ {};
template <typename Attribute, typename... T>
struct variant_has_substitute_impl<std::variant<T...>, Attribute>
{
typedef std::variant<T...> variant_type;
typedef typename mpl::transform<
mpl::list<T...>
, unwrap_recursive<mpl::_1>
>::type types;
typedef typename mpl::end<types>::type end;
typedef typename mpl::find<types, Attribute>::type iter_1;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<mpl::_1, Attribute>>,
mpl::identity<iter_1>
>::type
iter;
typedef mpl::not_<is_same<iter, end>> type;
};
template <typename Attribute, typename... T>
struct variant_find_substitute<std::variant<T...>, Attribute>
{
typedef std::variant<T...> variant_type;
typedef typename mpl::transform<
mpl::list<T...>
, unwrap_recursive<mpl::_1>
>::type types;
typedef typename mpl::end<types>::type end;
typedef typename mpl::find<types, Attribute>::type iter_1;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<mpl::_1, Attribute> >,
mpl::identity<iter_1>
>::type
iter;
typedef typename
mpl::eval_if<
is_same<iter, end>,
mpl::identity<Attribute>,
mpl::deref<iter>
>::type
type;
};
template <typename... T>
struct variant_find_substitute<std::variant<T...>, std::variant<T...> >
: mpl::identity<std::variant<T...> > {};
}
namespace x3 = boost::spirit::x3;
typedef std::variant<unsigned int, std::string> type_t;
static_assert(x3::traits::is_variant<type_t>{}, "");
static std::ostream & operator<<(std::ostream& o, type_t const & v)
{
if (std::holds_alternative<unsigned int>(v))
o << std::get<unsigned int>(v) << "\n";
else
o << std::get<std::string>(v) << "\n";
return o;
}
int main(void)
{
static_assert(x3::traits::is_variant<type_t>::value);
auto const parser
= x3::rule<struct parser_tag, type_t >{ "parser" }
= ('{' >> (x3::uint_ | x3::string("Hello")) >> '}');
type_t var;
std::string input("{12}");
bool v = x3::phrase_parse(input.begin(), input.end(), parser ,x3::space,var);
std::cout << "parsing : " << (v ? "OK" : "KO") << "\n";
std::cout << "var = " << var << "\n";
return 0;
}
解决方案
代码很好。改编只是没有定义为调试处理程序打印变体的方法。所以,评论
//#define BOOST_SPIRIT_X3_DEBUG
使其编译:http ://coliru.stacked-crooked.com/a/304122ff888cef2b
parsing : OK
var = 12
添加您自己的打印
跟踪代码显示 nonterminal/rule.hpp 包含 simple_trace.hpp,它使用 print_attribute 特征来打印内容。
namespace boost::spirit::x3::traits {
template <typename Out, typename T, typename Enable = void>
struct print_attribute_debug;
}
好的,让我们看看我们是否可以为我们的目的专门化这个特征:
namespace boost::spirit::x3::traits {
template <typename Out, typename... Ts>
struct print_attribute_debug<Out, std::variant<Ts...>, void> {
template <typename U>
static void call(Out& out, U const& value) {
std::visit([&out](auto const& v) {
x3::traits::print_attribute(out, v);
}, value);
}
};
}
成功
#include <iostream>
#include <variant>
#define BOOST_SPIRIT_X3_DEBUG
#include "boost/spirit/home/x3.hpp"
#include "boost/fusion/include/for_each.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace boost::spirit::x3::traits {
template<typename... T>
struct is_variant<std::variant<T...> >
: mpl::true_ {};
template <typename Attribute, typename... T>
struct variant_has_substitute_impl<std::variant<T...>, Attribute>
{
typedef std::variant<T...> variant_type;
typedef typename mpl::transform<
mpl::list<T...>
, unwrap_recursive<mpl::_1>
>::type types;
typedef typename mpl::end<types>::type end;
typedef typename mpl::find<types, Attribute>::type iter_1;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<mpl::_1, Attribute>>,
mpl::identity<iter_1>
>::type
iter;
typedef mpl::not_<is_same<iter, end>> type;
};
template <typename Attribute, typename... T>
struct variant_find_substitute<std::variant<T...>, Attribute>
{
typedef std::variant<T...> variant_type;
typedef typename mpl::transform<
mpl::list<T...>
, unwrap_recursive<mpl::_1>
>::type types;
typedef typename mpl::end<types>::type end;
typedef typename mpl::find<types, Attribute>::type iter_1;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<mpl::_1, Attribute> >,
mpl::identity<iter_1>
>::type
iter;
typedef typename
mpl::eval_if<
is_same<iter, end>,
mpl::identity<Attribute>,
mpl::deref<iter>
>::type
type;
};
template <typename... T>
struct variant_find_substitute<std::variant<T...>, std::variant<T...> >
: mpl::identity<std::variant<T...> > {};
}
namespace boost::spirit::x3::traits {
template <typename Out, typename... Ts>
struct print_attribute_debug<Out, std::variant<Ts...>, void> {
template <typename U>
static void call(Out& out, U const& value) {
std::visit([&out](auto const& v) {
x3::traits::print_attribute(out, v);
}, value);
}
};
}
namespace x3 = boost::spirit::x3;
typedef std::variant<unsigned int, std::string> type_t;
static_assert(x3::traits::is_variant<type_t>{}, "");
static std::ostream & operator<<(std::ostream& o, type_t const & v)
{
if (std::holds_alternative<unsigned int>(v))
o << std::get<unsigned int>(v) << "\n";
else
o << std::get<std::string>(v) << "\n";
return o;
}
int main(void)
{
static_assert(x3::traits::is_variant<type_t>::value);
auto const parser
= x3::rule<struct parser_tag, type_t >{ "parser" }
= ('{' >> (x3::uint_ | x3::string("Hello")) >> '}');
type_t var;
std::string input("{12}");
bool v = x3::phrase_parse(input.begin(), input.end(), parser ,x3::space,var);
std::cout << "parsing : " << (v ? "OK" : "KO") << "\n";
std::cout << "var = " << var << "\n";
return 0;
}
印刷
<parser>
<try>{12}</try>
<success></success>
<attributes>12</attributes>
</parser>
parsing : OK
var = 12
推荐阅读
- gcc - 为什么必须为特定目标配置 gnu binutils。下面发生了什么
- spring - 微服务还是连接到两个数据库?
- google-chrome - 从不同域调用身份验证 API 不会设置 cookie
- android - 离子角度奇怪的问题 - 自定义表单验证器未在 android 上被调用
- flutter - 在底部抽屉导航颤动中注销
- angular - 角 7 | 发布到 Google 表单
- antlr4 - 如何在antlr4中推送默认模式
- laravel - 脚本@php artisan package:discover --ansi 处理返回的自动加载转储后事件,错误代码为-1073741819
- javascript - 组件不处理空道具
- sql - 数据透视表查询问题。我在 django 中使用它作为 postgres 数据库的原始查询