Использование std::array в качестве атрибута для boost::spirit::x3
Я пытаюсь разобрать список чисел в фиксированный размер std::array
контейнер, использующий новейшую версию boost:: spirit x3 (как включено в boost 1.54). поскольку std::array
имеет необходимые функции, он определяется как контейнер, но ему не хватает функции вставки, что делает его несовместимым. Вот краткий пример того, что я пытаюсь сделать:
#include <boost/spirit/home/x3.hpp>
#include <array>
#include <iostream>
#include <string>
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
typedef std::array<double, 3> Vertex;
int main(int, char**) {
using x3::double_;
using ascii::blank;
std::string input = "3.1415 42 23.5";
auto iter = input.begin();
auto vertex = x3::rule<class vertex, Vertex>{} =
double_ >> double_ >> double_;
Vertex v;
bool const res = x3::phrase_parse(iter, input.end(), vertex, blank, v);
if (!res || iter != input.end()) return EXIT_FAILURE;
std::cout << "Match:" << std::endl;
for (auto vi : v) std::cout << vi << std::endl;
return EXIT_SUCCESS;
}
Это не скомпилируется с std::array
не имеет insert
функция. В качестве обходного пути я использовал семантические действия:
auto vertex() {
using namespace x3;
return rule<class vertex_id, Vertex>{} =
double_[([](auto &c) { _val(c)[0] = _attr(c); })] >>
double_[([](auto &c) { _val(c)[1] = _attr(c); })] >>
double_[([](auto &c) { _val(c)[2] = _attr(c); })];
}
а затем позвоните
x3::phrase_parse(iter, input.end(), vertex(), blank, v);
вместо. Это работает (используя clang 3.6.0 с -std= C++14), но я думаю, что это решение очень не элегантное и трудно читаемое.
Поэтому я попытался адаптировать std::array как последовательность слияния, используя BOOST_FUSION_ADAPT_ADT
вот так:
BOOST_FUSION_ADAPT_ADT(
Vertex,
(double, double, obj[0], obj[0] = val)
(double, double, obj[1], obj[1] = val)
(double, double, obj[2], obj[2] = val))
а затем специализируется x3::traits::is_container
чтобы Vertex сказал x3 не обрабатывать std::array как контейнер:
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<> struct is_container<Vertex> : public mpl::false_ {};
}}}}
Но это не скомпилируется в сочетании с x3. Это ошибка или я ее неправильно использую? Например fusion::front(v)
без всего кода x3 компилируется и работает, так что я думаю, что мой код не является полностью неправильным.
Тем не менее, я уверен, что для x3 есть более чистое решение, не включающее адаптеры fusion или семантические действия для этой простой проблемы.
1 ответ
Код, который вы разместили, пронизан ошибочными ошибками. Нет никаких оснований ожидать, что что-то там будет компилироваться, правда.
Несмотря ни на что, я убрал это ". Конечно, вы должны были включить
#include <boost/fusion/adapted/array.hpp>
К сожалению, это просто не работает. Я пришел к тому же самому заключению (попробовав то же самое, что вы упомянули, прежде чем прочитать об этом:)).
Это проблема юзабилити с Spirit X3, которая все еще находится в экспериментальной фазе. Вы можете сообщить об этом в списке рассылки [spirit-general]. Реакция обычно довольно быстрая.
¹ на тот случай, если вы хотите увидеть, с чем я работал http://paste.ubuntu.com/12764268/; Я также использовал x3::repeat(3)[x3::double_]
для сравнения.