2015-10-12 4 views
5

Я пытаюсь разобрать список чисел в контейнер с фиксированным размером std::array с использованием новейшего релиза boost :: spirit x3 (как указано в boost 1.54). Поскольку std::array имеет необходимые функции, он определяется как контейнер, но в нем отсутствует функция вставки, что делает ее несовместимой. Вот небольшой пример того, что я пытаюсь сделать:Использование std :: array as Attribute for boost :: spirit :: x3

#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), но я думаю, что это решение очень неэлегантно и трудно читается.

Так что я пытался адаптировать зЬй :: массива в виде последовательности слитой с использованием 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 не лечить зЬй :: массива в качестве контейнера:

namespace boost { namespace spirit { namespace x3 { namespace traits { 
    template<> struct is_container<Vertex> : public mpl::false_ {}; 
}}}} 

Но это не будет компилироваться в сочетании с x3. Является ли это ошибкой или я неправильно ее использую? Вызов, например. fusion::front(v) без кода x3 компилируется и работает, поэтому я предполагаю, что мой код не совсем ошибочен.

Однако я уверен, что есть более чистое решение с x3, не связанное с адаптерами или семантическими действиями для этой простой проблемы.

+0

Является ли 'boost :: array' опцией? Я считаю, что «boost/fusion/include/boost_array.hpp» «double_ >> double_ >> double_' должен работать. – llonesmiz

+0

Я исправил эти глупые ошибки, извините за это. 'boost :: array' не является параметром, так как я взаимодействую с существующим кодом, который в значительной степени зависит от' std :: array'. – ithron

+0

[Это ужасный хак] (http://coliru.stacked-crooked.com/a/412c97fecfa4e4b1), чтобы ваш подход скомпилировался. Вероятно, вам стоит подождать лучшего ответа (или действительно хорошего). – llonesmiz

ответ

0

Код, который вы опубликовали, пронизан небрежными ошибками. На самом деле нет причин ожидать чего-либо, чтобы компилироваться.

Независимо от этого, я очистил это. Конечно, вы должны были включить

#include <boost/fusion/adapted/array.hpp> 

К сожалению, это просто не работает. Я пришел к такому же выводу: (попробовав то же самое, о чем вы упомянули, прежде чем прочитать об этом :)).

Это проблема юзабилити с Spirit X3, которая все еще находится в экспериментальной фазе. Вы можете сообщить об этом в списке рассылки [spirit-general]. Ответ обычно довольно быстрый.


¹ в случае, если вы хотите увидеть, что я работал с http://paste.ubuntu.com/12764268/; Я также использовал x3::repeat(3)[x3::double_] для сравнения.

+0

К сожалению, 'std :: array' не адаптируется с помощью fusion. Предлагаемый вами заголовок (или «boost/fusion/include/boost_array.hpp») влияет только на «boost :: array». [This] (http://coliru.stacked-crooked.com/a/07416373f7d19da3), похоже, работает с некоторыми небольшими модификациями. [Здесь] (https://svn.boost.org/trac/boost/ticket/8241) - очень старая попытка адаптировать 'std :: array' (я понятия не имею, работает ли она еще). – llonesmiz

+0

Huh. Для меня это не сработало. Посмотрите на различия, когда у меня будет время позже. – sehe

+1

Аналогичная проблема существует для 'std :: forward_list'. 'push_back', необходимый для того, чтобы класс был контейнером с точки зрения Boost.Spirit. – Orient