4 Stimmen

Wie kann man von der Spirit::Qi-Regel aus auf boost::variant-Mitglieder zugreifen?

Ich kann keinen richtigen Weg finden, wie man auf Mitglieder von boost::variant mit boost::phoenix in meiner Spirit-Qi-Grammatik zugreifen kann. Hier ist einfach ein Beispiel, was ich versuche zu erreichen. (meine ganze Grammatik ist viel komplexer, dies ist ein einfaches Fragment, wo ich teste erwähnt Problem).

namespace ph = boost::phoenix;
typedef boost::variant<std::string,int> VariantType;
typedef std::list<VariantType> TlstVariants;

rule<Iterator, void(TlstVariants&), Skipper>    rule1;

rule1 = 
   qi::eps [ ph::push_back(qi::_r1, ph::construct<int>(2)) ]
>> qi::eps [ ph::get<int>(ph::back(qi::_r1)) = ph::val(3) ] //THIS IS EXAMPLE OF WHAT I NEED
;

TlstVariants lstVals;
ExecuteParser("5",rule1( ph::ref(lstVals) ));   

BOOST_FOREACH( VariantType &val, lstVals )
{
    std::cout << val.which() << " - " << val;
}

Aber ich kann keine phoenix::get<> oder eine ähnliche Methode finden, um mit Phoenix auf boost::variant zuzugreifen. Der Grund, warum ich phoenix::get<> benötige, ist, dass ich eine Variante mit einem bestimmten Typ in die Liste einfügen und dann diesen spezifischen Typ als Referenz an die untergeordnete Regel als geerbtes Attribut übergeben muss:

qi::rule<Iterator, void(structTest&), Skipper> rule_child;

rule = 
  qi::lit("test") [ph::push_back(sp::_r1, ph::construct<structTest>())]
> qi::lit('(') 
> rule_child( ph::get<structTest>(ph::back(sp::_r1)) ) 
> qi::lit(')') 
...

Gibt es eine Möglichkeit, dieses Verhalten zu erreichen?

Danke für jede Antwort

Rick

3voto

hkaiser Punkte 11260

Es ist ziemlich einfach, eine eigene "faule" Phoenix-Funktion zu schreiben. Hier ist eine für boost::variant .

#include <boost/variant.hpp>
#include <boost/spirit/include/phoenix.hpp>

template <typename Result>
struct get_impl
{
    template <typename T>
    struct result
    {
        typedef Result type;
    };

    template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
    Result operator()(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& v) const
    {
        return boost::get<Result>(v);
    }
};

ph::function<get_impl<int> > const get_int = get_impl<int>();

Dies kann nun in einer semantischen Aktion verwendet werden:

... qi::eps [ get_int(ph::back(qi::_r1)) = ph::val(3) ]

1voto

rickba Punkte 53

Ich glaube, ich habe einen Weg gefunden, wie man das machen kann. (Ich weiß nicht, ob das der beste Weg ist, aber es funktioniert ;-) ). Das Problem war der Typ int&, weil boost::variant int und nicht int& enthält. Also aktualisiere ich Ihre Vorlage, um zwei Typen zu akzeptieren, einen für variant getter und einen für return type.

I aktualisiert get_impl Vorlage auf diese Weise:

template <typename Result, typename Inner>
struct get_impl
{
    template <typename T>
    struct result
    {
        typedef Result type;
    };

    template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
    Result operator()(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & v) const
    {
        return boost::get<Inner>(v);
    }
};

Und meine Grammatik sieht jetzt so aus:

typedef boost::variant<std::string,int> VariantType;
qi::rule<DG_Iterator, void(VariantType&), DG_Skipper>   rule1;

ph::function<get_impl<int,int> >  const get_int = get_impl<int, int>();
ph::function<get_impl<int&,int> > const get_int_ref = get_impl<int&,int>();

rule1 = 
    qi::eps [ std::cout << ph::val("variant=") << qi::_r1 << ph::val("\n") ]
>> qi::eps [ std::cout << ph::val("before=") << get_int(qi::_r1) << ph::val("\n") ]
>> qi::eps [ get_int_ref(qi::_r1) = ph::val(7) ]
>> qi::eps [ std::cout << ph::val("after=") << get_int(qi::_r1) << ph::val("\n") ]
;

VariantType val(2134);
TestSimpleRuleValidity("x",rule1( ph::ref(val) ), true);    
std::cout << val << "\n";

Und alles scheint gut zu funktionieren. Nochmals vielen Dank, hkaiser, für Ihre erste Antwort, die mir sehr hilft.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X