Funktionstemplate mit beliebig vielen Parametern



  • 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.



  • GmbH schrieb:

    ...Sind Ellipsen bei Templateparametern nicht aber schöner/sicherer?...

    Ob sie schöner sind ist Geschmackssache, sicherer wenn du wirklich Elipsen meinst, sind sie nicht.

    Wenn wir aber nicht von Elipsen, sondern von Funktionen die zur Compilezeit vollständig aufgelöst werden reden (Über Variadic Templates in C++0x, soweit dies geht), und zur Laufzeit aber keine Elipsen mehr sind, magst du recht haben.

    cu André


  • Mod

    GmbH schrieb:

    Schade das dies im aktuellen Standard wohl nicht geht.

    Jedenfalls nicht ohne einigen Schreibaufwand, wobei man mit boosts preprocessor-Bibliothek wahrscheinlich viel einsparen kann - auf Kosten der Lesbarkeit: Man könnte für jeden Fall N=0,1,... des Funktionstyps mit N Parametern spezialisieren:

    template<typename T> class foo;
    template<typename R> class foo< R() >;
    template<typename R, typename P1> class foo< R (P1) >;
    template<typename R, typename P1, typename P2> class foo< R (P1,P2) >;
    template<typename R, typename P1, typename P2, typename P3> class foo< R (P1,P2,P3) >;
    template<typename R, typename P1, typename P2, typename P3, typename P4> class foo< R (P1,P2,P3,P4) >;
    // usw.
    

    Dabei muss es nicht unbedingt notwendig sein, das gesamte Template zu spezialisieren, wenn der Unterschied nur bei Memberfunktionen besteht, könnte man die Spezialisierung, resp. Überladung auch an dieser Stelle durchführen, ggf. Unterstützung durch SFINAE per enable_if.
    Ansonsten hilft tatsächlich nur das Warten auf den nächsten Standard oder, wenn es noch nicht Produktionscode sein muss, kann man auch mit g++ 4.3 experimientieren:

    template<typename T> class foo;
    template<typename R, typename ... P> class foo< R (P...) >;
    // usw.
    

    Was leider auch im nächsten Standard nicht möglich sein wird, ist eine derartige Flexibilität mit anderen Dingen als Typen zu ermöglichen. Mir würde zum Beispiel so ein einfacher "Funktorisierer" gefallen (Funktionen schreiben ist nun mal bequemer):

    template<auto /* meine Erfindung: soll jedes beliebige non-type-Argument akzeptieren */> struct Functor;
    template<typename R, typename ... P> struct Functor< R (*F)(P...) >
    {
        typedef R result_type;
        template<typename ... Args>
        R operator()(Args&&... args) const
        {
            return F( std::forward< Args >( args ) ... );
        }
    };
    

    Sehr viele Templates, die mit non-type-Parametern arbeiten, haben die Form

    template<typename T, T x> ...
    

    Dabei wäre die explizite Nennung des Typs eigentlich überflüssig - die notwendigen Mechanismen zur Typdeduktion besitzt der Compiler sowieso.


Anmelden zum Antworten