Funktionstemplate mit beliebig vielen Parametern



  • N'Abend alle zusammen.
    Das ist das Template

    template <typename T> T addieren (...)
    {
    	va_list params;
    	va_start (params, NULL);
    
    	T vars[50] = 0;
    	T result = 0;
    
    	int iParams;
    
    	for (; iParams < 50; iParams)
    		vars[iParams] = va_arg (params, T);
    
    	for (; iParams > 0; --iParams)
    		result += vars[iParams];
    
    	va_end (params);
    
    	return result;
    }
    

    Das Problem besteht darin, dass der Compiler immer meckert, dass ihm diese Funktion nicht bekannt ist

    Error E2285 main.cpp 14: Could not find a match for 'addieren<T>(int,int,int)' in function main()
    

    Hat jemand schonmal ein Template so verwendet, also mit beliebig vielen Parametern?

    Mfg Ominion



  • Du musst T explizit angeben, weil dein Compiler das verständlicherweise nicht deduzieren kann, sprich, er kann T nicht selbstständig herausfinden, wenn es nur im Rückgabewert vorkommt.



  • aber auch wenn ich das so mache geht es nicht:

    template <typename T> T addieren (T Sum1, ...)
    {
    	va_list params;
    	va_start (params, NULL);
    
    	T vars[50] = 0;
    	T result = 0;
    
    	int iParams;
    
    	for (; iParams < 50; iParams)
    		vars[iParams] = va_arg (params, T);
    
    	for (; iParams > 0; --iParams)
    		result += vars[iParams];
    
    	va_end (params);
    
    	return (result + Sum1);
    }
    

    es kommt immernoch die gleiche Fehlermeldung.

    Mfg Ominion



  • Ominion schrieb:

    es kommt immernoch die gleiche Fehlermeldung.

    Neee, es ist bestimmt nicht die selbe Fehlermeldung 😉

    Michael hat schon recht, du musst ein dummy Parameter reinhauen:

    template <typename T> T addieren (T dummy, ...)
    //... 
    va_start (params, dummy);
    //...
    

    Deine Funktion ist ehe von oben bis nach unten Fehlerhaft 😃
    Hier siehste du wie es sauber aussieht( obwohl ellipsen in C++ ja eh nicht sauber sind): http://www.pronix.de/pronix-814.html



  • ALSO, ertsmal warum glaubst du mir nicht? Es kommt immernoch der selbe Fehler, wenn ich versuche, diese Funktion als Template anzulegen. Normal geht das, dass war ja auch nicht die Frage.

    template <typename T> T addieren (T iResult, ...)
    {
    	va_list params;
    	va_start (params, iResult);
    
    	int vars = 0;
    
    	do
    	{
    		vars = va_arg (params, T);
    		iResult += vars;
    	}
    	while (vars != 0);
    
    	va_end (params);
    
    	return iResult;
    }
    

    So habe ich die jetzt verändert. Und es kommt immernoch der selbe Fehler, was aber an den Template liegt. Bloß jetzt nochmal die Frage: Wie kann ich ein Funktionstemplate mit beliebig vielen Parametern erstellen?

    Mfg Ominion



  • Funktioniert hier wunderbar. Du machst etwas falsch (tm).

    Evtl. hilft es ja, wenn Du uns main.cpp:14 einmal zeigst oder sagst, welche Zeile im geposteten Code die Zeile 14 ist?!



  • main.cpp:

    #include <iostream>
    #include "main_header.h"
    using namespace std;
    
    void wait ()
    { 
        cin.clear (); 
        cin.ignore (cin.rdbuf () -> in_avail ()); 
        cin.get (); 
    }
    
    int main ()
    {
    	int ad = addieren (5, 30, 11, 0); 
    
    	cout << ad;
    	wait ();
    
        return 0;
    }
    

    main_header.h:

    template <typename T> T addieren (T iResult, ...)
    {
    	va_list params;
    	va_start (params, iResult);
    
    	int vars = 0;
    
    	do
    	{
    		vars = va_arg (params, T);
    		iResult += vars;
    	}
    	while (vars != 0);
    
    	va_end (params);
    
    	return iResult;
    }
    

    Mfg Ominion



  • Das funktioniert mit dem MSVC++8 und dem GCC 4.1 ganz wunderbar. Damit bin ich auch raus, denn andere Compiler (inkl. Borland) habe ich derzeit nicht zu meiner Verfügung...



  • http://www.comeaucomputing.com/tryitout/ gibt keine Fehler im strict mode, nichts!

    In strict mode, with -tused, Compile succeeded



  • Klasse, aber das hilft mir jetzt auch nicht weiter...ist nur noch einmal eine Bestätigung, dass es bei mir nicht klappt...

    Mfg Ominion



  • Entschuldige dass wir versuchen Dein Problem nachzuvollziehen 😃

    Ernsthaft, bisher ist das für mich ein Hinweis darauf dass der Borland-Compiler "etwas anders macht" (TM) als die drei im Thread genannten. Solange Du nicht scharf drauf bist, den Compiler zu wechseln, kannst Du jetzt höchstens noch abwarten, ob sich irgendein "Borländer" zu einem möglichen Workaround äußert.



  • Wenn man den Typ mit angibt, klappts auch mit einem Borland-Compiler (BCB6).

    int ad = addieren<int>(5, 30, 11, 0);
    


  • Bei mir (BCC 5.82.0) funktioniert es, wenn ich den Argumenttyp explizit angebe (dann klappt auch die erste Version, bei der nur die Ellipse als Parameter angegeben ist):

    addieren <int> (12, 34, 56, 78, 0);
    

    edit: zweite Seite nicht gesehen 🙄

    Wenn das bei dir nicht geht, aktualisiere mal den Compiler; der BCC 5.5.1 ist mit nunmehr 7 Jahren schon ein wenig ältlich.



  • Doch, danke es funktioniert jetzt endlich. Ich werde mir auch gleich mal den neueren Compiler runterladen.

    Mfg Ominion

    EDIT: Kannst du mir vllt. einen Link zu dieser Version schicken? Weil auch auf der Website finde ich auch nur 5.5.1



  • Ominion schrieb:

    EDIT: Kannst du mir vllt. einen Link zu dieser Version schicken? Weil auch auf der Website finde ich auch nur 5.5.1

    Der BCC 5.82 ist in Turbo C++ 2006 enthalten.



  • Ich habe ein Problem, daß ich im Template auch beliebige viele Parameter nutzen möchte, allerdings soll dies eine Klasse sein und für diese klasse wiederum eine Memberfunktion mit entsprechenden Parametern erstellt werden. Im Prinzip möchte ich im Template Typ die Signatur ein Memberfunktion beschreiben. Diese soll alles abbilden von void foo() bis zu Rückgabetypen mit vielen Parametern.

    template <typename TN1, ...>
    class
    {
       void foo( TN1, ... )
       {
          bar( TN1, ...);
       };
    };
    

    Meine Lösung kreiste aber immer um etwas wie Obiges, funktionierte aber bisher nie. Im Netz habe ich zwei Beispiele gesehen für einen Aufruf aber leider keine Lösung gesehen. Einmal wird void foo(int, int) über das Template als <void (int, int)> genutzt, ein anderes mal <void, int, int>. Unterschieden sie die beiden Aufrufe in der Template-Definition? Bzw. wie würde man es richtig machen.

    Jemand eine Idee, wie man das löst? Also dem Template beliebige Parameter und Rückgabetyp für eine Funktion mitgeben, die dann implementieren wird?

    Nutze gcc-4.1.2.



  • GmbH schrieb:

    ...template <typename TN1, ...> class {...

    Ohne dir jetzt deinen Fehler gänzlich beseitigen zu können (ich verwende niemals Elipsen, und das mit guten Grund...).

    1. Dir fehlt mindestens ein Klassenname für das Template
    2. Nach einer Methodendefinition brauchst du kein Semikolon
    3. Ich weiß nicht ob es mit Elipsen geht, aber wenn du Klassen verwendest wäre eine const Referenz in der Regel deutlich sinnvoller als Copy-By-Value

    GmbH schrieb:

    Jemand eine Idee, wie man das löst? Also dem Template beliebige Parameter und Rückgabetyp für eine Funktion mitgeben, die dann implementieren wird?

    Hast du schon mal an die Empfehlung gedacht, lieber Vektoren (o.ä.) von Werten als Elipsen zu verwenden?

    cu André



  • 1. & 2. - klar 😞 das kommt davon wenn man eine Anschauungsklasse ebenso so runter schreibt.
    3. Stimmt, mir ging es aber erstmal um die Funktionalität.

    Mit Vektoren als Ellipsen wird das bei mir ziemlich sicher nicht funktionieren da einige Schnittstellen fremdgesteuert sind. Sind Ellipsen bei Templateparametern nicht aber schöner/sicherer? Es wird doch eine komplette Klasse für jede vorhandene Parameterkombination eindeutig implementiert und nicht dynamisch die Parameter rausgesucht?



  • template<typename ...Args>
    

    Variadic Templates kommen erst mit dem nächsten Standard C++0x, siehe auch den Artikel zu C++09 hier im C++Magazin.

    <void (int, int)>
    

    Da wird irgendwas mit Funktionszeigern gemacht. Ich hab mal eben ein Template geschrieben, dass man auf diese Art instanzieren kann:

    #include <iostream>
    
    template<typename T>
    class Test
    {
        public:
            Test(T t) : func(t) {} // Konstruktor bekommt Funktion übergeben
            T* func; // Funktionszeiger
    };
    
    void function(int a, int b)
    {
        std::cout << a << "+" << b << "=" << (a+b) << std::endl;
    }
    
    int main()
    {
        Test<void (int, int)> test(function); // Template instanzieren
        test.func(2, 3); // Funktion aufrufen
    }
    

    Was das aber bringen soll ist mir nicht klar.



  • Danke, allerdings hilft mir diese Notation eines Funktionspointers wohl doch nicht, denn ich brauche Rückgabetyp und Parameterliste um damit abhängig der Parameter jeweils Funktionen in der Templateklasse zu implementieren. Ich will nicht bloß diese Funktion aufrufen, ich brauche wenn ich ein Template damit baue

    <void (int, int)>
    

    auch eine Funktion in der Klasse mit

    void templateClassFunction(int, int);
    

    die vom Template gebaut wird.

    Schade das dies im aktuellen Standard wohl nicht geht.


Log in to reply