Variadische Template-Argumente verodern.



  • camper schrieb:

    Hier eine nicht-rekursive Variante

    template<class... Rest>
    struct Or
    {
        template<typename IteratorType>
        static bool match(IteratorType begin, IteratorType end,
            IteratorType& newBegin)
        {
            bool result = false;
            const bool matched[] = { result = result || Rest::match(begin, end, newBegin)...};
            return (void)matched, result;
        }
    };
    

    Uh. Wie funktioniert das? Die pack expansion erstreckt sich "einfach so" auf den kompletten Ausdruck inklusive Veroderung? Oder fehlen da noch Klammern?

    { (result = result || Rest::match(begin, end, newBegin))...}
    

    Und wozu beim return nochmal matched anführen? - damit irgendwas instantiiert wird?


  • Mod

    pumuckl schrieb:

    camper schrieb:

    Hier eine nicht-rekursive Variante

    template<class... Rest>
    struct Or
    {
        template<typename IteratorType>
        static bool match(IteratorType begin, IteratorType end,
            IteratorType& newBegin)
        {
            bool result = false;
            const bool matched[] = { result = result || Rest::match(begin, end, newBegin)...};
            return (void)matched, result;
        }
    };
    

    Uh. Wie funktioniert das? Die pack expansion erstreckt sich "einfach so" auf den kompletten Ausdruck inklusive Veroderung? Oder fehlen da noch Klammern?

    Klammern wären fürs Lesen besser, habe ich nur versehentlich vergessen. Erforderlich sind sie allerdings nicht.
    Es gibt keine Packexpansion für Ausdrücke per se (wenn es sie gäbe, bräuchten wir das Array ja nicht). Die relevante Expansion hier ist

    n3337 schrieb:

    initializer-list:
    initializer-clause ...opt
    initializer-list , initializer-clause ...opt

    pumuckl schrieb:

    { (result = result || Rest::match(begin, end, newBegin))...}
    

    Und wozu beim return nochmal matched anführen? - damit irgendwas instantiiert wird?

    Nur um eine Warnung wegen nicht verwendeter lokaler Variablen loszuwerden.



  • camper schrieb:

    Es gibt keine Packexpansion für Ausdrücke per se (wenn es sie gäbe, bräuchten wir das Array ja nicht). Die relevante Expansion hier ist

    n3337 schrieb:

    initializer-list:
    initializer-clause ...opt
    initializer-list , initializer-clause ...opt

    Alles klar, note to myself: pack expansion nochmal genauer ansehen 🙂



  • @Camper: Aber ruft der Ausdruck dann nicht match() für alle Template-Argumente auf?


  • Mod

    Ethon schrieb:

    @Camper: Aber ruft der Ausdruck dann nicht match() für alle Template-Argumente auf?

    Sofern match fehlschlägt, sicher?
    pumuckls Version hat das Problem, das keine Kurzschlussauswertung erfolgt.



  • Ethon schrieb:

    @Camper: Aber ruft der Ausdruck dann nicht match() für alle Template-Argumente auf?

    Ich hab mich auch gefragt, was da pssiert, und es wie folgt getestet:

    #include <iostream>
    using namespace std;
    
    template<class... Rest>
    struct Or
    {
        template<typename IteratorType>
        static bool match(IteratorType begin, IteratorType end,
            IteratorType& newBegin)
        {
            bool result = false;
            cout << "or::match - ";
            const bool matched[] = { result = result || Rest::match(begin, end, newBegin)...};
            return (void)matched, result;
        }
    };
    
    struct T { static bool match(char*, char*, char*&) {cout << "T::match - ";
    return true;} };
    struct F { static bool match(char*, char*, char*&) {cout << "F::match - ";
    return false;} };
    
    int main()
    {
      char hw[] = "Hello, World!";
      char* const e = hw + sizeof(hw);
      char* ptr = 0;
    
      typedef Or<F,F,T> OT1;
      cout << OT1::match(hw, e, ptr) << '\n';
    
      typedef Or<F,T,F> OT2;
      cout << OT2::match(hw,e,ptr) << '\n';
    
      typedef Or<T,F,OT1> OT3;
      cout << OT3::match(hw,e,ptr) << '\n';
    }
    

    Output:

    or::match - F::match - F::match - T::match - 1
    or::match - F::match - T::match - 1
    or::match - T::match - 1
    

    Heißt, die späteren matches werden nicht mehr aufgerufen.
    Was da nach packexpansion quasi steht ist ja auch folgendes (bei Or<F,T,F>)

    const bool matched[] = 
    { result = result || F::match(begin, end, newBegin),
      result = result || T::match(begin, end, newBegin),
      result = result || F::match(begin, end, newBegin)};
    

    Nach Auswertung einzelner matches heißt das eben

    const bool matched[] = 
    { result = false || false,
      result = false || true,
      result = true || <never mind...>};
    

Anmelden zum Antworten