Klassentemplate spezialisieren



  • Das versteh ich nicht ganz, und warum kommt man hier immer mit Java. Ich hab nichts mit Java am Hut.

    Und für mich ist das ganz bestimmt kein Schwachsinn. Wenn ich nicht möchte, dass man eine Klassen-Instanz machen kann, ist diese Art und weise genau das Richtige. Und wie schon geschrieben, ich hab meine Gründe, warum ich das so gestalte.

    Aber um nochmals auf das Problem zu kommen. Templates haben doch auch den Vorteil, dass man mehrere Typen durch eine Funktion schläusen kann. Das ist genau meine Ziel. z.b für Typen int, double und long etc.

    Es stört mich aber, dass ich für jeden Typ trotzdem eine eigene Funktion schreiben muss, daher auch meine Frage.

    gruss wachs



  • Nebenbei Funk2 in lesbar:

    bool Class1<bool>::Funk2(bool bol) { return !bol; }
    


  • Ja danke Jockelx

    Ich hab mein If-statement halt noch nicht optmiert, den es geht mri ja nicht um die If-Anweisung.



  • Funk1 musst du doch gar nicht spezialisieren. Die macht doch immer das Gleiche.
    Bei Funk2 wirst du wohl nicht drum herum kommen, solange die was unterschiedliches machen.



  • wachs schrieb:

    Das versteh ich nicht ganz, und warum kommt man hier immer mit Java. Ich hab nichts mit Java am Hut.

    Und für mich ist das ganz bestimmt kein Schwachsinn. Wenn ich nicht möchte, dass man eine Klassen-Instanz machen kann, ist diese Art und weise genau das Richtige. Und wie schon geschrieben, ich hab meine Gründe, warum ich das so gestalte.

    Aber um nochmals auf das Problem zu kommen. Templates haben doch auch den Vorteil, dass man mehrere Typen durch eine Funktion schläusen kann. Das ist genau meine Ziel. z.b für Typen int, double und long etc.

    Es stört mich aber, dass ich für jeden Typ trotzdem eine eigene Funktion schreiben muss, daher auch meine Frage.

    gruss wachs

    Ich verstehe nicht, warum man das als Schwachsinn titulieren muss. Man kann ja auch respektvoller miteinander umgehen.

    Der Einwand bezieht sich darauf, dass es in C++ in der Regel keinen Sinn macht, eine Klasse zu definieren, die man nie instantiieren kann. Wozu brauche ich so eine Klasse dann? Willst Du nur statische Methoden, klingt das so, als wolltest Du die Klasse als Rahmen verwenden und dafür sind tatsächlich namespaces gedacht.

    Und zum eigentlichen Problem: Im Prinzip ist das so, dass eine Spezialisierung eine eigene Klasse ist, wo ich alles nochmal definieren muss. Die Teillösung wäre, eine typunabhängige Basisklasse zu schaffen. Ein Beispiel aus der Standardlibrary das std::ios_base und std::basic_ios<char_type> .



  • Hi!

    ich fand es bei C++ auch schon oft unhandlich, dass wenn man nur einen Teil der Methoden spezialisieren möchte, das nur mit der ganzen Klasse machen kann, und nicht nur für einen Teil der Methoden (wobei dann für die nicht spezialisierten Methoden die generische Methode verwendet würde).

    Ich denke mal, das deine Frage darauf hinaus läuft? Dass du die Spezialisierung eigentlich nur für Funk1 und Funk2 benötigst, und für alles andere die generische Variante verwendet werden soll?

    Ich löse sowas oft, indem ich nicht die eigentliche Klasse spezialisiere, sondern eine Hilfsklasse, die den eigentlich wichtigen Code der Methoden enthält. Z.B. so (exemplarisch für Funk1, analog für Funk2):

    namespace detail
    {
        // Hier die Idee: Hilfsklassen verwenden.
        template <typename T>
        struct Funk1Helper
        {
            // Generische Variante. func() kann hier evtl. auch
            // undefiniert sein, wenn nur bool und double zulässig sind. 
            // Dann gibt es einen Compiler-Fehler, wenn ein anderer
            // Typ verwendet wird
            static T func(bool bol)
            {
                return T();
            }
        };
    
        // Spezialisierung für bool.
        template <>
        struct Funk1Helper<bool>
        {
            static bool func(bool bol)
            {
                return false;
            }
        };
    
        // Spezialisierung für double.
        template <>
        struct Funk1Helper<double>
        {
            static double func(bool bol)
            {
                return 5.1;
            }
        };
    }
    
    template <typename T>
    class Class1{
    private:
        // Oha! Grad gesehen, privater Konstruktor und Desktruktor,
        // ich hoffe du weisst wie eingeschränkt man die Klasse dann
        // nur verwenden kann und hast einen guten Grund dafür ;-)
        Class1();
        Class1(const Class1 &obj);
        ~Class1();
    
        ...
    
    public:
        static T Funk1(bool bol)
        {
            // Der Trick: der Funktionsaufruf wird hier einfach an
            // die (deutlich simplere) Hilfsklasse weitergeleitet.
            return detail::Funk1Helper<T>::func(bol);
        }
    };
    

    Das hat den Vorteil, dass man nur die simple Funk1Helper -Klasse spezialisieren muss, und ansonsten für andere Methoden in Class1 auf die generische Implementierung (mit T ) zurückgreift.

    Gruss,
    Finnegan

    P.S.:

    manni66 schrieb:

    Wozu benötigst du ein Template, wenn du nur zwei Klassen für double und bool willst?
    Wozu eine Klasse ohne Membervariablen?
    Leerer Konstruktor, Copykonstruktor und Destruktor? Warum?
    Wozu die static Funktionen?

    Ich weiss nicht weshalb du überhapt antwortest, wenn du eine klar gestellte Frage dabei nicht beantwortest. Ich kann in der Originalfrage jedenfalls nirgendwo die Einschränkung auf bool und double erkennen, und dass die Klasse exemplarisch ist, sollte eigentlich schon aus den Bezeichnern hervorgehen :p

    Finnegan



  • manni66 schrieb:

    wachs schrieb:

    Static, weil ich Klassenmethoden möchte. (darum auch Konstruktoren etc. private)

    In Java muss man das so machen, in C++ ist das Schwachsinn. Benutze namespace.

    Ich würde mal gerne eine Begründung dafür hören, weshalb statische Methoden "Schwachsinn" sein sollen? In meinen Augen machen diese Sinn, wenn die Funktion logisch eng mit der Klasse verknüpft ist. Warum nicht zusammen schreiben was zusammen gehört? Z.B.:

    template <typename T, std::size_t N>
    class QuadraticMatrix
    {
       public:
           ...
           static QuadraticMatrix identity();
    }
    
    ...
    auto m = QuadraticMatrix<float, 4>::identity();
    ...
    

    Was ist daran schlechter Code? Warum sollte es besser identity() in einen Namespace zu packen (was ich besonders in diesem Fall eher für eine umständliche Krücke halte)?

    Finnegan



  • Finnegan schrieb:

    Ich würde mal gerne eine Begründung dafür hören, weshalb statische Methoden "Schwachsinn" sein sollen? In meinen Augen machen diese Sinn, wenn die Funktion logisch eng mit der Klasse verknüpft ist. Warum nicht zusammen schreiben was zusammen gehört? Z.B.:

    template <typename T, std::size_t N>
    class QuadraticMatrix
    {
       public:
           ...
           static QuadraticMatrix identity();
    }
    
    ...
    auto m = QuadraticMatrix<float, 4>::identity();
    ...
    

    Was ist daran schlechter Code? Warum sollte es besser identity() in einen Namespace zu packen (was ich besonders in diesem Fall eher für eine umständliche Krücke halte)?

    Finnegan

    Das ist sicher OK. Ich finde auch, dass statische Methoden ein nettes Feature ist. Es geht ja darum, dass die Klasse ausschliesslich aus statischen Methoden besteht und sie explizit nicht instantiierbar sein soll:

    wachs schrieb:

    ...Wenn ich nicht möchte, dass man eine Klassen-Instanz machen kann, ...



  • Guten Tag Finnegan

    Danke für das Beispiel.

    Es kommt zwar in deinem Beispiel noch eine weitere Funktion (die Hilfsfunktion) hinzu, aber es ist eigentlich genau das was ich suche.

    Danke und gruss

    wachs



  • tntnet schrieb:

    Das ist sicher OK. Ich finde auch, dass statische Methoden ein nettes Feature ist. Es geht ja darum, dass die Klasse ausschliesslich aus statischen Methoden besteht und sie explizit nicht instantiierbar sein soll:

    wachs schrieb:

    ...Wenn ich nicht möchte, dass man eine Klassen-Instanz machen kann, ...

    Ah... das hatte ich überlesen. Allerdings macht es dennoch kaum einen Unterschied, ich wüsste zumindest nicht, dass es sowas wie Template-Namespaces gäbe. Die Funktionen sollen ja scheinbar abhängig von einem Template-Parameter sein, da halte ich das durchaus für legitim. Ich glaube sogar std::numeric_limits macht so etwas ähnliches wie es wachs haben möchte.

    Gruss,
    Finnegan



  • wachs schrieb:

    Guten Tag Finnegan

    Danke für das Beispiel.

    Es kommt zwar in deinem Beispiel noch eine weitere Funktion (die Hilfsfunktion) hinzu, aber es ist eigentlich genau das was ich suche.

    Danke und gruss

    wachs

    Gern. Der zusätzliche Code lässt sich nicht wirklich vermeiden, allerdings finde ich, dass es nur unwesentlich mehr Code ist, als wenn man die Funktionen direkt spezialisieren könnte (lediglich in ein struct {} eingerahmt.)

    Gruss,
    Finnegan


Anmelden zum Antworten