[C++] Template Spezialisierung

DerSpud

Commodore Special
Mitglied seit
01.09.2003
Beiträge
356
Renomée
1
Standort
Baden
Ich hab hier ein kleines Problem mit der Template Syntax. Vielleicht ist das Konstrukt so auch gar nicht möglich. Vielleicht kann mir einer von euch sagen wo der Denkfehler ist oder wie die richtige Syntax aussieht.

Hier mal ein vereinfachter Code:
Code:
template<typename T>
class BaseClass {
/*...*/
public:
  template<unsigned int var>
  static BaseClass* Create();
};

Eine abgeleitete Klasse soll nun eine spezialisierte Version von Create() für ein bestimmtes 'var' implementieren, welche ein Objekt der abgeleiteten Klasse erzeugt, castet und zurückgibt. Jetzt ist das Problem, wie sieht die spezialisierte Version aus?

Mein erster Ansatz:
Code:
template<typename T>
inline BaseClass<T>* BaseClass<T>::Create<1>() {
	return static_cast<BaseClass<T>*>(new DerivedClass<T>());
}
Ich hab schon einige Sachen ausprobiert aber es will einfach nicht funktionieren.
Wo ist der Fehler? *noahnung*
 
Das ist aber ein wildes Konstrukt. Allerdings glaube ich nicht, dass es Spezialisierungen für bestimmte Werte gibt. Ich kenne Template-Spezialisierungen nur für bestimmte Datentypen.
Zumindest habe ich davon noch nie gelesen. Aber ich lasse mich da gerne eines Besseren belehren ;D

/edit: Das würde ja auch bedeuten, dass zur Laufzeit der Methodenaufruf bestimmt werden muss. Kannst also genauso mit einer IF-Abfrage in der Create-Methode machen.
 
Zuletzt bearbeitet:
Man könnte das auch mit Typspezialisierung anstatt mit einem Wert machen, das Problem bliebe das gleiche:

Wie sieht die Syntax für ein Funktionstemplate in einem Klassentemplate aus? Irgendwie find ich dazu nix. *noahnung*

Die if-Abfrage würde natürlich auch gehen, aber da müssten die Implementierungen der Basisklasse bekannt sein und man müsste die Create-Methode ändern wenn eine neue Implementierung dazu kommt.
Zur Zeit inkludier ich immer nur eine bestimmte Implementierung über #ifdef, das geht natürlich auch. Das Ziel war das mithilfe von Templates dynamischer zu machen.
 
Es wäre interessant zu wissen was du machen willst. Ich kann mir beim besten Willen nicht vorstellen, wo der Sinn hinter so einem Konstrukt liegt.
Du hast eine statische Methode. Das bedeutet ja, dass sie nur auf statische Membervariablen zugreifen kann. Oder wolltest du eine globale Funktion? Dann deklarier sie außerhalb der Klasse.
Du überschreibst eine Funktion in einer Kindklasse. Du solltest sie dann auch virtual deklarieren.
Bei Klassentemplates steht das template<typename T> vor der Deklaration der Klasse und nicht vor der Deklaration der Methoden. Und dann nochmal vor der jeder Methodendefinition.

Und Typspezialisierung gibt es, aber keine Wertspezialisierung.
 
Es wäre interessant zu wissen was du machen willst. Ich kann mir beim besten Willen nicht vorstellen, wo der Sinn hinter so einem Konstrukt liegt.
Du hast eine statische Methode. Das bedeutet ja, dass sie nur auf statische Membervariablen zugreifen kann. Oder wolltest du eine globale Funktion? Dann deklarier sie außerhalb der Klasse.
Du überschreibst eine Funktion in einer Kindklasse. Du solltest sie dann auch virtual deklarieren.

Ich habe eine abstraktes Thread-Interface von dem es verschiedene Implementationen gibt, z.B. QThread, Win32-Threads oder pthreads. Als Anwender benutze ich nur das Interface und erzeuge mir mit Thread::Create() eine Instanz. Die static-Methode macht genau das wie im Beispiel oben, ich greife also auf keine Member der Klasse zu.
Bisher wird durch z.B. vorheriges #define USE_WIN32_THREADS bei einem Create() ein Win32-Thread erzeugt.

Die Implementationen leiten die Klasse zwar ab, aber nicht die Create() Funktion, da die ja statisch ist, sie implementieren die Funktion nur. Deshalb kann ich zur Zeit auch immer nur eine Implementation benutzen.

Durch die Templates will ich eben gleichzeitig mehrere Implementationen nutzen können.
Da die Create()-Funktion static ist wollte ich durch Spezialisierung und nicht durch Vererbung die verschiedenen Implementation bereitstellen.

Bei Klassentemplates steht das template<typename T> vor der Deklaration der Klasse und nicht vor der Deklaration der Methoden. Und dann nochmal vor der jeder Methodendefinition.
Man muss meines Wissens das template<typename T> nochmal vornedran schreiben, weil die Definition nicht gleich in der Klassendeklaration erfolgt. Ich habe also zwei Templates ein Klassentemplate und ein Funktionstemplate und das ist was die Syntax so verwirrend macht. *noahnung*

Und Typspezialisierung gibt es, aber keine Wertspezialisierung.
Ok, das war mir neu.

Oder wolltest du eine globale Funktion?
Das scheint mir zur Zeit die einzige Möglichkeit zu sein. Wollte halt einen Bezug zur Klasse, könnte man aber auch mit einem Namespace machen.
 
Zuletzt bearbeitet:
Hi,

du bist da m.e. mit templates ziemlich am ziel vorbeigeschossen...

Das ist eher ein klassisches OO Problem :).
Code:
class ThreadBase
{};

class QTThread : public ThreadBase
{};

class MSWThread : public ThreadBase
{};

class ThreadFactory
{
public:
 enum ThreadId{ QTThread, MSWThread };

  static ThreadBase *createThread(ThreadId id)
  {
    switch (id)
    {
      case QTThread:
        return new QTThread();
      (...)
    }
  }
};

Das ist jetzt aus dem hangelenk geschrieben und garantiert mit syntax fehlern gesät, aber das prinzip sollte klar sein.

Du solltest jeder klasse einen virtuellem destructor verpassen, um keine memory leaks zu fangen. Ich würde die statische factory funktion auch unbedingt in die cpp packen und dort die wrapper includen, das erspart dir evntl. stress mit dem compiler.

Gruss
 
Jo, damit könnte ich mehrere Implementationen nebeneinander nutzen. Das Problem dabei ist wiederum das nicht alle Implementationen immer verfügbar sind (z.b. Win32-Threads auf Linux ), also werde ich um die hässliche #ifdefs nicht herumkommen.

Das wollte ich eigentlich mit den Templates vermeiden. Aber das scheint mir inzwischen auch ein bisschen zuviel Aufwand für den geringen Nutzen. :)

Jedenfalls weiß ich jetzt warum meine erster Lösungsansatz nicht funktioniert hat:
Man kann nur von einer bestimmten Templateinstanz ein inneres Template spezialisieren.

Thx für die Antworten
 
Zuletzt bearbeitet:
Moin,

plattformübergreifende Threads liefert dir die BOOS lib; bin damit und mit anderen sachen von denen recht glücklich.

Gruss,
 
Hmm, ich wollte die Threads auch auf nem embedded Microcontroller + FreeRTOS benutzen können und da ist eine riesige Bibliothek nicht unbedingt sinnvoll.

Aber klar, auf nem PC würde ich Boost benutzen oder direkt die Qt-Threads, welche ja auch nur ein Wrapper um die pthread Bibliothek sind.
 
Yo...um embedded mache ich lieber einen bogen :).

Allerdings wollte ich nur noch anmerken, dass die boost nicht monolitisch ist, kannst also auch nur einzelne libs mit ins Projekt nehmen (boost_thread ist bei mir auf x86 30kb groß). Ob und wie du sie übersetzten kannst....k.a. :).
 
Eine abgeleitete Klasse soll nun eine spezialisierte Version von Create() für ein bestimmtes 'var' implementieren, welche ein Objekt der abgeleiteten Klasse erzeugt, castet und zurückgibt. Jetzt ist das Problem, wie sieht die spezialisierte Version aus?

Unbeachetet der Frage, ob das hier sinnvoll ist, bist du demnhttp:ach auf der Suche nach object factories.

Dieses Pattern erlaubt einen generischen Ansatz, Objekte von konkreten Klassen zu erstellen, in einer großen Dynamik.

Eine solche factory besitzt i. d. R. eine registrier, eine unregistrier und eine create-Funktion als Schnittstelle. Zudem hält sie eine map vor, die eine id mit einem Creator verknüpft.
Eine interessante und wie ich finde gute Implementierung findest du in Loki ( - hier wäre eine Link zu Loki, allerdings darf ich mit 2 Beiträgen keinen Link posten, deshalb musst du selbst nach Loki C++ suchen ;) ), eine ausführliche Beschreibung in "Modern C++ Design" von Andrei Alexandrescu.


Hoffe, dir weitergeholfen zu haben ;)

Gruß,

badday
 
Zurück
Oben Unten