Возможно ли дать это ограничение в GCC для написания класса посетителя для примера кода, который я включил, чтобы можно было удалить материал ostream?
Конечно. В основном я вижу три подхода:
1. Добавить шаблон машины
Вы можете специализировать детали реализации, случайно требуемые GCC:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
};
namespace std {
template <> struct variant_size<value> :
std::variant_size<value::base_type> {};
template <size_t I> struct variant_alternative<I, value> :
std::variant_alternative<I, value::base_type> {};
}
Посмотреть в прямом эфире на Wandbox (GCC 8.1)
Расширение пространства имен std чревато (хотя я думаю, что это законно для
пользовательские типы). Таким образом, вы можете использовать мой любимый шаблон и скрыть
e std::visit
отправка в сам объект функции:
template <typename... El>
void operator()(std::variant<El...> const& v) const { std::visit(*this, v); }
Теперь вы можете просто вызвать функтор, и он автоматически отправит
на свой собственный тип, производный от варианта, потому что перегрузка operator()
делает
НЕ есть проблемы, которые есть у GCC stdlib:
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
3. Сделайте вещи явными
Мне это нравится меньше всего, но оно имеет свои достоинства: нет магии и нет
приемы:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
// ...
Опять в прямом эфире
РЕЗЮМЕ
Подумав немного больше, я бы рекомендовал последний подход из-за относительной простоты. Умный - это часто кодовый запах:)
Полный список для будущих посетителей:
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
std::ostream& _os;
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
void operator()(float const& f) const { _os << "float:" << f; }
void operator()(int const& i) const { _os << "int:" << i; }
void operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) {
operator()(el);
_os << ",";
}
_os << ']';
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def = "tuple" >> x3::lit(':') >> ("[" >> value_ % "," >> "]");
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point = x3::skip(x3::space) [ value_ ];
}
int main()
{
for (std::string const str : {
"float: 3.14",
"int: 3",
"tuple: [float: 3.14,int: 3]",
"tuple: [float: 3.14,int: 3,tuple: [float: 4.14,int: 4]]"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}