C++ runterbrechen von nested variant

jkallup

Erfahrenes Mitglied
Hallo,
wie kann man vernestetete variants runtersplitten?
in der operator + member, mekkert der g++ compiler.
wäre für sachdienliche hinweise und problem lösern dankbar

Code:
    struct add_ { };
    struct sub_ { };
    struct mul_ { };
    struct div_ { };

    struct expr   { };
    struct sconst { };
    struct mconst { };

    template <typename OpTag1> struct binary_op;
    template <typename OpTag2> struct cmd_print;
    template <typename OpTag3> struct cmd_varset;

    template <typename OpTag> struct TypeDouble;
    template <typename OpTag> struct TypeDoublePrint;

    typedef boost::variant<
      double
    , std::string

    , boost::recursive_wrapper< binary_op<add_> >
    , boost::recursive_wrapper< binary_op<sub_> >
    , boost::recursive_wrapper< binary_op<mul_> >
    , boost::recursive_wrapper< binary_op<div_> >

    , boost::recursive_wrapper< cmd_varset<TypeDouble     <int> > >
    , boost::recursive_wrapper< cmd_print <TypeDoublePrint<int> > >
    > expression;


    expression& operator + (expression& exp1, expression& exp2) {
        std::cout << "plus" << std::endl;

        std::cout << "------" << std::endl;
        std::cout << typeid(exp1).name() << std::endl;
        std::cout << typeid(exp2).name() << std::endl;
        std::cout << "======" << std::endl;

        expression tmp1 = boost::get<expression>(exp1);
        expression tmp2 = boost::get<expression>(exp2);

        cmd_varset<TypeDouble<int> > td1 = boost::get<cmd_varset<TypeDouble<int> > >(tmp1);
        cmd_varset<TypeDouble<int> > td2 = boost::get<cmd_varset<TypeDouble<int> > >(tmp2);

        TypeDouble<int> td3 = boost::get<TypeDouble<int> >(td1);
        TypeDouble<int> td4 = boost::get<TypeDouble<int> >(td2);

        double d1 = boost::get<double>(td3);
        double d2 = boost::get<double>(td4);

        double res = d1 + d2;

        expression tmp = res;
        return tmp;
    }

Gruß
jens
 

cwriter

Erfahrenes Mitglied
wie kann man vernestetete variants runtersplitten?
Was verstehst du unter "runtersplitten"? Die einzelnen Werte extrahieren? Da werden eigentlich die visitors empfohlen.
http://www.boost.org/doc/libs/1_55_0/doc/html/variant/tutorial.html



in der operator + member, mekkert der g++ compiler.
Würde ich aber auch ;)
1) Der Rückgabetyp ist eine Referenz. Du gibst eine lokale Variable zurück -> Kawumms ist das Programm kaputt.
2) Wieso hat TypeDouble ein template, das auf int gesetzt wird? Leuchtet mir jetzt nicht gerade so ein.
3) boost.get<expression>: Deine Variant hat ja gar keine Expressionmember? Was erhoffst du dir von diesem Code?
4) Sollten variants nicht nur ein einziges Objekt gleichzeitig halten können? Wie soll es gehen, alle Möglichkeiten auszulesen? Willst du nicht die Pointervariante von get (wie im Tutorial) verwenden?

Was sagt denn der Compiler genau? Was passt ihm nicht?

Gruss
cwriter
 

jkallup

Erfahrenes Mitglied
Hallo,

die Funktion schaut inzwischen do aus:
Code:
    expression operator + (expression const exp1, expression const exp2) {
        std::cout << "plus" << std::endl;

        std::cout << "------" << std::endl;
        std::cout << typeid(exp1).name() << std::endl;
        std::cout << typeid(exp2).name() << std::endl;
        std::cout << "======" << std::endl;

        cmd_varset<TypeDouble<int> > td1 = exp1.;
        cmd_varset<TypeDouble<int> > td2 = boost::get<cmd_varset<TypeDouble<int> > >(exp2);

        TypeDouble<int> td3 = td1.value;
        TypeDouble<int> td4 = td2.value;

        double d1 = td3.value;
        double d2 = td4.value;

        double res = d1 + d2;
        expression tmp = res;
        return     tmp;
    }

Die Zeile:
cmd_varset<TypeDouble<int> > td1 = exp1.;

da meckert der Compiler;
und in der Zeile:

cmd_varset<TypeDouble<int> > td2 = boost::get<cmd_varset<TypeDouble<int> > >(exp2);

da wird compiliert ohne Frage ode meckern,
allerdings während der Laufzeit, da knallt es.
 

cwriter

Erfahrenes Mitglied
da meckert der Compiler;
Naja, steht ja auch keine Member hinter dem Punkt?

Was ist expression denn jetzt?
Sollte das nicht "const expression(&) exp1" in den Parametertypen heissen?

allerdings während der Laufzeit, da knallt es.
Was ist, wenn exp nicht von diesem Typ ist?
Entweder für jedes get sowas schreiben:
C:
if(typ1* v = boost::get<typ1>(&exp))
{
//mach was hier
}
Oder halt die erwähnten visitors verwenden.

Was du momentan machst, ist:
"Hey, ich will die Murmeln aus der Dose".
"Äh, da sind keine Murmeln drin? Was soll ich jetzt geben? -> Crash".
Was get in der Pointervariante tut:
"Hey, ich will die Murmeln aus der Dose".
"Sind keine drin. Kriegst einen nullptr zurück."
"Ok, dann gibt mir die Kekse."
"Ah ja, hier sind sie."

Gruss
cwriter
 

jkallup

Erfahrenes Mitglied
Hallo,

if (cmd_varset<TypeDouble<int> > *tmp1 = boost::get<cmd_varset<TypeDouble<int> > >(&exp1))

meinst du das so?
er macht an dieser stelle einen abbruch - bad get
 

cwriter

Erfahrenes Mitglied
Sofern das
C:
typedef boost::variant<
      double
    , std::string

    , boost::recursive_wrapper< binary_op<add_> >
    , boost::recursive_wrapper< binary_op<sub_> >
    , boost::recursive_wrapper< binary_op<mul_> >
    , boost::recursive_wrapper< binary_op<div_> >

    , boost::recursive_wrapper< cmd_varset<TypeDouble     <int> > >
    , boost::recursive_wrapper< cmd_print <TypeDoublePrint<int> > >
    > expression;
noch gilt, müsste es so aussehen

C:
if (boost::recursive_wrapper<cmd_varset<TypeDouble<int>>> *tmp1 = boost::get<boost::recursive_wrapper<cmd_varset<TypeDouble<int>>>>(&exp1))

bad_get wird ja nur dann geworfen, wenn ein Typ verlangt wurde, den es nicht geben kann.

Gruss
cwriter
 

jkallup

Erfahrenes Mitglied
dann schaut das so aus:

Code:
parser_sbase.cc: In Funktion »kallup::expression kallup::operator+(const expression&, const expression&)«:
parser_sbase.cc:242:67: Fehler: ungültige Umwandlung von »boost::add_pointer<const boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > > >::type {aka const boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >*}« in »boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >*« [-fpermissive]
             boost::get<boost::recursive_wrapper<cmd_varset<TypeDouble<int>>>>(&exp1))
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
 

cwriter

Erfahrenes Mitglied
dann schaut das so aus:
Er scheint sich ja nur über einen fehlenden const-qualifier zu beschweren.

Geht das hier?
C:
if (const boost::recursive_wrapper<cmd_varset<TypeDouble<int>>> *tmp1 = boost::get<boost::recursive_wrapper<cmd_varset<TypeDouble<int>>>>(&exp1))

Gruss
cwriter

/EDIT: Wobei sich add_pointer eher nach dem &exp1 anhört... Ist exp1 immer noch vom Typ expression?
/EDIT2: Oh, du hast eine const reference auf exp1. Dann müsste es wohl so aussehen:

C:
if (const boost::recursive_wrapper<cmd_varset<TypeDouble<int>>> *tmp1 = boost::get<const boost::recursive_wrapper<cmd_varset<TypeDouble<int>>>>(&exp1))
 
Zuletzt bearbeitet:

jkallup

Erfahrenes Mitglied
das schaut schon recht vernüftiger aus:

[CODE}
if (const
boost::recursive_wrapper<cmd_varset<TypeDouble<int>>> *tmp1 =
boost::get<
boost::recursive_wrapper<cmd_varset<TypeDouble<int>>>>(&exp1))
[/CODE]

Allerdings hier:

[CODE}
/usr/local/include/boost/variant/get.hpp: In Instanziierung von »typename boost::add_pointer<const U>::type boost::strict_get(const boost::variant<T0, TN ...>*) [with U = boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >; T0 = double; TN = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::recursive_wrapper<kallup::binary_op<kallup::add_> >, boost::recursive_wrapper<kallup::binary_op<kallup::sub_> >, boost::recursive_wrapper<kallup::binary_op<kallup::mul_> >, boost::recursive_wrapper<kallup::binary_op<kallup::div_> >, boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >, boost::recursive_wrapper<kallup::cmd_print<kallup::TypeDoublePrint<int> > >}; typename boost::add_pointer<const U>::type = const boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >*]«:
/usr/local/include/boost/variant/get.hpp:277:25: erfordert durch »typename boost::add_pointer<const U>::type boost::get(const boost::variant<T0, TN ...>*) [with U = boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >; T0 = double; TN = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::recursive_wrapper<kallup::binary_op<kallup::add_> >, boost::recursive_wrapper<kallup::binary_op<kallup::sub_> >, boost::recursive_wrapper<kallup::binary_op<kallup::mul_> >, boost::recursive_wrapper<kallup::binary_op<kallup::div_> >, boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >, boost::recursive_wrapper<kallup::cmd_print<kallup::TypeDoublePrint<int> > >}; typename boost::add_pointer<const U>::type = const boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >*]«
parser_sbase.cc:244:73: required from here
/usr/local/include/boost/variant/get.hpp:203:5: Fehler: statische Erklärung gescheitert: boost::variant does not contain specified type U, call to boost::get<U>(const boost::variant<T...>*) will always return NULL
BOOST_STATIC_ASSERT_MSG(
^
make: *** [parser_sbase.o] Fehler 1
jens@rechner1 ~/Projekte/keyBase/src $

[/CODE]
 

cwriter

Erfahrenes Mitglied
Fehler: statische Erklärung gescheitert: boost::variant does not contain specified type U, call to boost::get<U>(const boost::variant<T...>*) will always return NULL
Sagt es ja eigentlich: Der Typ ist nicht vorhanden.
[with U = boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >
Behauptet, dass dieser Typ nicht existiert. Aber
TN = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::recursive_wrapper<kallup::binary_op<kallup::add_> >, boost::recursive_wrapper<kallup::binary_op<kallup::sub_> >, boost::recursive_wrapper<kallup::binary_op<kallup::mul_> >, boost::recursive_wrapper<kallup::binary_op<kallup::div_> >, boost::recursive_wrapper<kallup::cmd_varset<kallup::TypeDouble<int> > >, boost::recursive_wrapper<kallup::cmd_print<kallup::TypeDoublePrint<int> > >};
behauptet, dass es vorhanden ist...

Hm. Wie geht's damit?

C:
if (auto tmp1 = boost::get<const boost::recursive_wrapper<cmd_varset<TypeDouble<int>>>>(&exp1))
(nach http://www.boost.org/doc/libs/1_58_0/doc/html/boost/get_idp295310448.html muss das const in den Typ U übertragen werden, wenn die Expression constant-qualified ist.)

Gruss
cwriter