Variadic Templates



  • Hallo zusammen,

    kann mir bitte jemand helfen, ich habe gerade über Variadic Templates gelesen und erhalte folgenden Fehler, der vermutlich offensichtich ist, aber mir ist mein Fehler einfach nicht klar.

    template< typename T >
    void f(const T& s)
    {
        cout << s;
    }
    
    template< typename T, typename... Tail >
    void print(const T& head, const Tail&... tail)
    {
        cout << head << "\n\n";
        f(tail...);
    }
    
    int main()
    {
        print<string, string, string, string>("Hello", "World", "How are you", "today");
    }
    
    ||=== Build: Debug in Test (compiler: GNU GCC Compiler) ===|
    In instantiation of 'void print(const T&, const Tail& ...) 
    [with T = std::basic_string<char>; Tail = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]':
    error: no matching function for call to 'f(const std::basic_string<char>&, const std::basic_string<char>&, const std::basic_string<char>&)'
    note: candidate is:
    note: template<class T> void f(const T&)
    note:   template argument deduction/substitution failed:
    note:   candidate expects 1 argument, 3 provided
    

    Ich spüre wie offensichtlich der Fehler wohl sein muss, aber ich bekomms einfach nicht gebacken. Hab schon auf verschiedene Arten versucht `print` anzuwenden, aber es klappt nie.



  • Tail... ist:
    std::string, std::string, std::string

    also rufst du f so auf:

    f("World"s, "How are you"s, "today"s)
    

    es gibt aber nur ein "f" das einen Parameter übernimmt.

    Quick and dirty in-Forum Lösung:

    void print () {} // ein Parameter pack kann auch nichts enthalten
    
    template< typename T, typename... Tail >
    void print(const T& head, const Tail&... tail) 
    {
        cout << head << "\n\n";
        print(tail...); // neues head = erstes Element aus tail und der Rest ist der neue tail.
        // (Anmerkung: Das ist keine "echte" Rekursion, da die Funktionen alle unterschiedlicher Signatur sind und damit unterschiedliche Funktionen)
    }
    
    int main()
    {
        print ("Hello", "World", "How are you", "today");
    }
    


  • Hui, wieso brauch ich denn keine Template Parameter für print? Erkennt der Compiler diese selbst?

    In dem Buch war auch so etwas mit einer gleichnamigen Funktion, die nichts macht und verwendet wird, aber ich verstehs nicht so ganz^^

    Ich werd mir wohl das Ganze nochmal gründlich durchlesen müssen, auf jeden Fall sehe ich jetzt, dass ich es nicht wie im Code-Beispiel gemacht hatte und daher gab es Probleme.



  • Hier Schritt für Schritt:

    void print() {};
    
    template <typename T, typename ... List>
    void print(T head, List... tail)
    {
        print(tail...);
    };
    
    int main()
    {
        print (1, 2, 3, 4);
    }
    

    (Folgendes ist kein C++, sondern nur zur Veranschaulichung)

    Erster Aufruf "print(1, 2, 3, 4)":
    head = 1
    tail... = 2, 3, 4

    Zweiter Aufruf "print(2, 3, 4)" (innerhalb von print<int, int, int, int>):
    head = 2
    tail... = 3, 4

    Dritter Aufruf "print(3, 4)" (innterhalb von print<int, int, int>):
    head = 3
    tail... = 4

    Vierter Aufruf "print(4)" (innerhalb von print<int, int>):
    head = 4
    tail... = LEER

    Fünfter Aufruf "print()" (innerhalb von print<int>):
    // rufte print ohne parameter auf, weil das Parameterpack "tail..." leer war.
    // Hiermit ist "print" fertig.



  • Achso, also diese leere, gleichnahmige Funktion dient dem, dass wenn das Ganze fertig ist (keine Parameter mehr), einfach "nichts" gemacht wird, und danach ist es sozusagen "Abgebrochen".



  • HarteWare schrieb:

    Achso, also diese leere, gleichnahmige Funktion dient dem, dass wenn das Ganze fertig ist (keine Parameter mehr), einfach "nichts" gemacht wird, und danach ist es sozusagen "Abgebrochen".

    Ja. Wie die Abbruchbedingung einer Rekursion. Gäbe es das "leere" print() nicht, würde der Compiler auch beim letzten Schritt meckern, da in diesem Fall print(tail...); zu print(); expandiert wird und nicht aufgelöst werden kann, da es nur eine print-Funktion gibt, die mindestens ein Argument erwartet:
    void print( T head , List... tail)

    Finnegan


Log in to reply