Variadische Template-Argumente verodern.



  • Sorry Hacker. 😉

    mit den üblichen C++-Semantiken (Abbruch der Evaluierung sobald 1 Wert wahr etc).

    So ähnlich ist es mir zunächst auch in den Sinn gekommen.



  • Ethon schrieb:

    Sorry Hacker. 😉

    mit den üblichen C++-Semantiken (Abbruch der Evaluierung sobald 1 Wert wahr etc).

    So ähnlich ist es mir zunächst auch in den Sinn gekommen.

    Stopp! 💡
    ➡ Eigenes count !



  • Also sowas, wie wäre es damit?

    bool one_of(std::initializer_list<bool> const& b)
    {
            for(auto const val : b)
                    if(val)
                            return true;
    
            return false;
    }
    
    template<typename IterT,
             typename First,
             typename Second,
             typename ... Rest>
    bool Or(IterT begin,
            IterT end,
            IterT& newBegin)
    {
            return one_of({First::match(begin, end, newBegin), Second::match(begin, end, newBegin), Rest::match(begin, end, newBegin)...});
    }
    


  • Das verhindert aber nicht, dass du sämtliche Bedingungen evaluierst, sondern nur, dass du dir alle Ergebnisse anguckst.
    Und das gibt es (seit C++11) schon und heißt std::any_of .



  • ipsec schrieb:

    Das verhindert aber nicht, dass du sämtliche Bedingungen evaluierst, sondern nur, dass du dir alle Ergebnisse anguckst.
    Und das gibt es (seit C++11) schon und heißt std::any_of .

    Tja, hab ich beides schon geahnt... 😞

    Tja, neh, dann geht nur die rekursive Variante, hast Recht Ethon.



  • Sone schrieb:

    Eisflamme schrieb:

    variadisch

    Korrekte Übersetzung, Du Kichererbse. 😉

    Aha, aber

    Du zitierst Wörterbücher, die nicht Mal den englischen Begriff kennen, und lachst dann über die Übersetzung?

    http://www.dict.cc/?s=variadic



  • edit: zu spät...



  • Eisflamme schrieb:

    Sone schrieb:

    Eisflamme schrieb:

    variadisch

    Korrekte Übersetzung, Du Kichererbse. 😉

    Aha, aber

    Du zitierst Wörterbücher, die nicht Mal den englischen Begriff kennen, und lachst dann über die Übersetzung?

    http://www.dict.cc/?s=variadic

    Nein, eigentlich wollte ich damit andeuten dass das alles eine sinnlose Diskussion wird, weil es den begriff variadic gar nicht gibt... anscheinend gibt es ihn doch...

    Wie auch immer: variadisch fand' ich einfach nur lustig, nicht falsch o. ä.



  • Sone schrieb:

    Nein, eigentlich wollte ich damit andeuten dass das alles eine sinnlose Diskussion wird, weil es den begriff variadic gar nicht gibt...

    Selbst wenn er in keiner Übersetzungsseite aufgetaucht wäre, ist er im Standard fest definiert, jeder hier weiß, was gemeint ist (auch mit der deutschen Übersetzung), und das einzig sinnlose ist, dass du ne Diskussion darüber vom Zaun gebrochen hast 😛

    PS, wozu oben überhaupt initializer_list?

    template <unsigned N>
    constexpr bool any_of(const bool* arr)
    {
      return (N == 0) ? false : 
               ((N==1) ? (*arr): (any_of<N/2>(arr) || any_of<N-N/2>(arr+N/2)));
    }
    
    template<class... Rest>
    struct Or
    {
        template<typename IteratorType>
        static bool match(IteratorType begin, IteratorType end,
            IteratorType& newBegin)
        {
            const bool matched[] = {Rest::match(begin, end, newBegin)...};
            return any_of<sizeof...(Rest)>(matched);
        }
    };
    
    struct T { static constexpr bool match(char*, char*, char*&) {return true;} };
    struct F { static bool match(char*, char*, char*&) {return false;} };
    
    #include <iostream>
    using namespace std;
    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,F,F> OF1;
      cout << OF1::match(hw,e,ptr) << '\n';
    
      typedef Or<F,F,OF1> OF2;
      cout << OF2::match(hw,e,ptr) << '\n';
    
      cout << Or<>::match(hw,e,ptr) << '\n';
    }
    

  • Mod

    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;
        }
    };
    
    struct T { static constexpr bool match(char*, char*, char*&) {return true;} };
    struct F { static bool match(char*, char*, char*&) {return false;} };
    
    #include <iostream>
    using namespace std;
    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,F,F> OF1;
      cout << OF1::match(hw,e,ptr) << '\n';
    
      typedef Or<F,F,OF1> OF2;
      cout << OF2::match(hw,e,ptr) << '\n';
    
      cout << Or<>::match(hw,e,ptr) << '\n';
    }
    


  • 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