将 Boost Spirit 解析器从 boost::variant 过渡到 std::variant 2
Transitioning Boost Spirit parser from boost::variant to std::variant 2
我试图让 x3 解析器使用 std::variant
而不是 boost::variant
,但没有成功。
我遵循了关于这个主题的 post: 但是让它工作所需的样板在我的情况下似乎不起作用。 (简化的)错误消息指出:
std::variant<...> has no member named apply_visitor
我承认,但是这个锅炉板对我来说太不明飞行物了,我无法修复它。
这是重现我的问题的最小测试代码,available on 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
我试图让 x3 解析器使用 std::variant
而不是 boost::variant
,但没有成功。
我遵循了关于这个主题的 post:
std::variant<...> has no member named apply_visitor
我承认,但是这个锅炉板对我来说太不明飞行物了,我无法修复它。
这是重现我的问题的最小测试代码,available on 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