2015-10-12 2 views
5

J'essaye d'analyser une liste de nombres dans un conteneur de taille fixe std::array en utilisant la version la plus récente de boost :: spirit x3 (incluse dans boost 1.54). Depuis std::array a les fonctions nécessaires, il est détecté comme un conteneur, mais il lui manque la fonction d'insertion qui le rend incompatible. Voici un court exemple de ce que je suis en train d'accomplir:Utilisation de std :: array comme attribut pour 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; 
} 

Ce ne sera pas compilé depuis std::array n'a aucune fonction insert. Pour contourner ce problème je les actions sémantiques:

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); })]; 
} 

puis appelez

x3::phrase_parse(iter, input.end(), vertex(), blank, v); 

à la place. Cela fonctionne (en utilisant clang 3.6.0 avec -std = C++ 14), mais je pense que cette solution est très inélégante et difficile à lire.

J'ai donc essayé d'adapter std :: tableau comme une séquence de fusion en utilisant BOOST_FUSION_ADAPT_ADT comme ceci:

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)) 

puis spécialisée x3::traits::is_container pour Vertex de dire x3 de ne pas traiter std :: tableau comme un conteneur:

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

Mais cela ne compilera pas en combinaison avec x3. Est-ce un bug ou est-ce que je l'utilise mal? L'appel par ex. fusion::front(v) sans tout le code x3 compile et fonctionne, donc je suppose que mon code n'est pas complètement faux.

Cependant, je suis sûr qu'il existe une solution plus propre avec x3 n'impliquant pas d'adaptateurs de fusion ou d'actions sémantiques pour ce problème simple.

+0

Est-ce que 'boost :: array' est une option? Je crois y compris "boost/fusion/include/boost_array.hpp" 'double_ >> double_ >> double_' devrait fonctionner. – llonesmiz

+0

J'ai corrigé ces erreurs stupides, désolé pour ça. 'boost :: array' n'est pas une option car j'interface un code existant qui repose fortement sur' std :: array'. – ithron

+0

[Ceci est un hack terrible] (http://coliru.stacked-crooked.com/a/412c97fecfa4e4b1) pour rendre votre approche compilée. Vous devriez probablement attendre une meilleure réponse (ou en fait une bonne réponse). – llonesmiz

Répondre

0

Le code que vous avez posté est criblé d'erreurs bâclées. Il n'y a aucune raison de s'attendre à quelque chose à compiler, vraiment.

Peu importe, j'ai nettoyé ça¹. Bien sûr, vous auriez dû inclure

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

Malheureusement, cela ne fonctionne tout simplement pas. Je suis arrivé en grande partie à la même conclusion que (après avoir essayé les mêmes choses que vous mentionnez, avant de lire à ce sujet :)).

Ceci est un problème d'utilisation avec Spirit X3 - qui est encore en phase expérimentale. Vous pouvez le signaler à la liste de diffusion [spirit-general]. La réponse est généralement assez rapide.


¹ au cas où vous voulez voir ce que je travaillais avec http://paste.ubuntu.com/12764268/; J'ai également utilisé x3::repeat(3)[x3::double_] pour la comparaison.

+0

Malheureusement, 'std :: array' n'est pas adapté par fusion. L'en-tête que vous suggérez (ou "boost/fusion/include/boost_array.hpp") n'affecte que "boost :: array". [This] (http://coliru.stacked-crooked.com/a/07416373f7d19da3) semble fonctionner avec quelques petites modifications. [Ici] (https://svn.boost.org/trac/boost/ticket/8241) est une très vieille tentative d'adaptation de 'std :: array' (je ne sais pas si ça marche encore). – llonesmiz

+0

Huh. Cela n'a pas fonctionné pour moi. Regardera les différences quand j'ai le temps plus tard. – sehe

+1

Un problème similaire existe pour 'std :: forward_list'. 'push_back' requis pour que la classe soit conteneur en termes de Boost.Spirit. – Orient