2016-07-05 2 views
8

Ce code ne compile (gcc 5.3.1 SURCPL 1,60):Esprit X3, l'action sémantique fait compilation échoue avec: attribut n'a pas la taille attendue

#include <boost/spirit/home/x3.hpp> 

namespace x3 = boost::spirit::x3; 

template <typename T> 
void parse(T begin, T end) { 
    auto dest = x3::lit('[') >> x3::int_ >> ';' >> x3::int_ >> ']'; 

    auto on_portal = [&](auto& ctx) {}; 
    auto portal = (x3::char_('P') >> -dest)[on_portal]; 

    auto tiles = +portal; 
    x3::phrase_parse(begin, end, tiles, x3::eol); 
} 

int main() { 
    std::string x; 
    parse(x.begin(), x.end()); 
} 

Il échoue avec une assertion statique:

error: static assertion failed: Attribute does not have the expected size. 

Grâce à wandbox j'ai également essayé 1.61 boost et clang, les deux produisent les mêmes résultats.

Si je supprime l'action sémantique attachée à portal, il compile bien; la même chose se produit si je change dest à:

auto dest = x3::lit('[') >> x3::int_ >> ']'; 

Toute aide serait appréciée. TIA.

+1

Ce reproducteur est excellent. J'aime quand les gens réduisent le problème à l'essentiel. +10 si je pouvais – sehe

Répondre

4

Cela me surprend aussi, je le signalerais sur la liste de diffusion (ou le bug tracker) comme un bug potentiel.

Pendant ce temps, vous pouvez "réparer" en fournissant un type d'attribut pour dest:

Live On Coliru

#include <boost/fusion/adapted/std_tuple.hpp> 
#include <boost/spirit/home/x3.hpp> 
#include <iostream> 

namespace x3 = boost::spirit::x3; 

template <typename T> 
void parse(T begin, T end) { 
    auto dest = x3::rule<struct dest_type, std::tuple<int, int> > {} = '[' >> x3::int_ >> ';' >> x3::int_ >> ']'; 

    auto on_portal = [&](auto& ctx) { 
     int a, b; 
     if (auto tup = x3::_attr(ctx)) { 
      std::tie(a, b) = *tup; 
      std::cout << "Parsed [" << a << ", " << b << "]\n"; 
     } 
    }; 
    auto portal = ('P' >> -dest)[on_portal]; 

    auto tiles = +portal; 
    x3::phrase_parse(begin, end, tiles, x3::eol); 
} 

int main() { 
    std::string x = "P[1;2]P[3;4]P[5;6]"; 
    parse(x.begin(), x.end()); 
} 

Prints:

Parsed [1, 2] 
Parsed [3, 4] 
Parsed [5, 6] 

NOTE J'ai changé char_('P') en juste lit('P') parce que je ne voulais pas compliquer l'exemple traitant du caractère dans l'attribut. Peut-être que vous ne vouliez pas l'avoir dans l'attribut exposé de toute façon.

+0

Merci pour la solution de contournement! – dvd

+0

Y a-t-il un surcoût d'avoir à configurer les variables de grammaire (comme 'tiles') à chaque fois que' parse() 'est appelé? Serait-il préférable d'avoir une 'classe parse' avec (peut-être' static') les membres qui peuvent être initialisés une fois et ensuite les réutiliser sur plusieurs appels? Cela faciliterait également la fourniture de vos propres analyseurs dans du code en-tête uniquement. – TemplateRex

+0

Je ne pense pas que la majorité du code soit important, car tout peut être en ligne. "tiles" n'existera probablement jamais. Si vous voulez utiliser des analyseurs fournis par le client, alors vous voulez, par définition, effacer le type. C'est le territoire de IYAM 'x3 :: any_parser'. Si vous voulez juste logiquement regrouper des règles (en cachant tout sauf le point de départ), je le renverrais simplement d'une fonction. X3 n'a aucun problème avec cela, par opposition à Qi – sehe