Seite 1 von 2

"dynamische" Templates

Verfasst: 21. April 2010 11:31
von hmroessler
Hallo zusammen,

ich habe eine abstrakte Basisklasse "Camera". Ein Member dieser Klasse wird per Templateparameter typisiert. Soweit kein Problem.

Wenn ich jetzt allerdings, einen Camerapointer in meiner MainWindow Klasse einfüge, kenne ich den Templatetype nicht. Ich kenn diesen erst, wenn ich weiss, welche Subklasse ich dem Camerapointer zuweisen kann.

Bsp.:

Code: Alles auswählen

class MainWindow : public QMainWindow {
    Q_OBJECT

private:
  Ui::MainWindow *ui;
  Camera<T> *camera;

public:
  //wegen Übersichtlichkeit inline
  MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
  this->setAttribute(Qt::WA_DeleteOnClose);
  this->ui->setupUi(this);

  //welche Kamera darf es denn sein?
  if(camera1) {
    this->camera = new Camera1(); //Hier müsste T z.B. ein HIDS sein
  } else {
    this->camera = new Camera2(); //Und hier z.B. ein int*
  }
}
Vielen Dank und viele Grüße
Holger M. Rößler

Verfasst: 21. April 2010 11:38
von Christian81
Da müsstest Du dem MainWindow ctor bzw. die Klasse auch als Template bauen.
Was aber total unnötig ist. Das ganze geht viel bequemer komplett ohne Template mit Hilfe einer Factory und einer Basisklasse von der alle Kameras ableiten.

Verfasst: 21. April 2010 12:15
von RHBaum
Das ganze geht viel bequemer
Aber Christian, Du solltest doch wissen das "Bequemlichkeit" in der SW-Entwicklung niemals Grundlage einer Entscheidung sein sollte :twisted:

@hmroessler
Verwendest du dein Widget jemals mit mehreren Typen im selben binary oder wird dein QMainWindow immer nur mit ein bestimmten T laufen ?
Also unter welchen umstaenden kann sich T aendern, aus sicht der Applikation ?

Ciao ...

Verfasst: 21. April 2010 12:22
von Christian81
RHBaum hat geschrieben:
Das ganze geht viel bequemer
Aber Christian, Du solltest doch wissen das "Bequemlichkeit" in der SW-Entwicklung niemals Grundlage einer Entscheidung sein sollte :twisted:
Hehe :)
Sagen wirs mal so - sein aktueller usecase sieht nicht nach einem typischen Template-Fall aus und eine Factory + abstrakte Basisklasse ist wohl eher das was er sucht und auch leichte zu implementieren :)

Verfasst: 21. April 2010 13:32
von franzf
Wenn es dann jetzt WIRKLICH eine template-basierte Lösung sein MUSS, kann man einfach mal einen Blick in boost::any werfen. Ist nicht wirklich viel zu Lesen und zu Verstehen :)

Verfasst: 21. April 2010 14:33
von hmroessler
Hallo,

erstmal vielen Dank für eure raschen und kompetenten Antworten.

Vielleicht habe ich das Problem auch schlecht geschildert:

Ich habe eine abstrakte Basisklasse "Camera", von der konkrete Kameraklassen abgeleitet werden. Camera soll einenen Member "cameraHandle" beinhalten, der aber je nach Teiber ein anderer Datentypen ist. Um mir nun unnötige casterein zu ersparen, würde ich diesen Parameter in der Basisklasse Camera unterbringen und diesen per Template typisieren.

Code: Alles auswählen

template<class T>
class Camera {
private:
  T cameraHandle;
  
//...much more code...
};
Nun kann jede Subklasse den Typen T anders Typisieren, je nachdem welcher Datentyp vom Kameratreiber benötigt wird. Soweit auch kein Problem. Nun wird ein "Camera" Member in die MainWindow Klasse eingefügt:

Code: Alles auswählen

class MainWindow //....etc. {
private:
  Camera<T> *camera; //Der benötigte Typ T ist hier noch nicht bekannt!
  
public:
  MainWindow() { //inline der Übersicht zuliebe
     //..Auslesen der Konfigurationsdatei
    if(neededCamera == kamera1) {
      this->camer<int> = new Kamera1(); //T muss int sein
   } else if(neededCamera == kamera2) {
      this->camaer<HIDS> = new Kamera2();//T muss HIDS sein
   }
 }
};
Wie hier unschwer zu sehen, kann erst im Konstruktor entschieden werden, welcher Typ T für Camera<T> verwendet wird.


@Christian81
Da müsstest Du dem MainWindow ctor bzw. die Klasse auch als Template bauen.
Was aber total unnötig ist. Das ganze geht viel bequemer komplett ohne Template mit Hilfe einer Factory und einer Basisklasse von der alle Kameras ableiten.
Eine Basisklasse gibt es ja bereits (Camera). Nur sehe ich hier nicht, wie eine Factory das Problem mit dem Template lösen soll. Das Problem besteht doch darin, dass ich bei der deklaration des Basisklassenzeiger nicht weiss, welchen Templateparametertypen er zugewiesen bekommt, sondern erst bei der instanzierung.

@RHBaum
Verwendest du dein Widget jemals mit mehreren Typen im selben binary oder wird dein QMainWindow immer nur mit ein bestimmten T laufen ?
Also unter welchen umstaenden kann sich T aendern, aus sicht der Applikation ?
Je nach Konfiguration wird im Konstruktor entschieden, welcher Kameratyp erzeugt werden soll. Bei jedem Kameratyp kann der Templatetyp anders sein. Das Widget selbst hat damit ja nichts zu tun, sondern nur ein nicht visuelles Objekt, das von Kamera abgeleitet ist.
Das Kameraobjekt stellt quasi nur die Verbindung zwischen Programm und den verschiedenen möglichen Kameratreibern dar.

@franzf
Wenn es dann jetzt WIRKLICH eine template-basierte Lösung sein MUSS, kann man einfach mal einen Blick in boost::any werfen. Ist nicht wirklich viel zu Lesen und zu Verstehen
Vielleicht wäre das ein Weg. Aber diesen würde ich nur sehr ungerne gehen, da ich wirklich nur externe Libs einbinden will, wenn es absolut nicht anders geht.

Das muss doch mit C++ Bordmitteln zu lösen sein!? :shock:

Vielen Dank und viele Grüße
hmroessler

Verfasst: 21. April 2010 14:57
von Christian81
Sorry aber Deine Ausführungen haben mir immer noch keinen einzigen Grund geliefert warum hier ein template nötig ist...

Code: Alles auswählen

template class<T>
configCamera()
{
  this->camera = new Camera<T>();
}

Verfasst: 21. April 2010 15:09
von hmroessler
Hi Christian,
Sorry aber Deine Ausführungen haben mir immer noch keinen einzigen Grund geliefert warum hier ein template nötig ist...
Wenn du einen alternativen Weg kennst, mit dem ich den Member "cameraHandle" in der Basisklasse "Camera" von den abgeleiteten Kameraklassen aus zu typisieren, bin ich ganz Ohr.

Vielen Dank und viele Grüße
hmroessler

Verfasst: 21. April 2010 15:14
von Christian81
Habe ich doch schon gesagt - abstrakte Basisklasse und fertig...
Außerdem sollte mein Funktionsaufruf auch gehen.

Verfasst: 21. April 2010 15:30
von hmroessler
Habe ich doch schon gesagt - abstrakte Basisklasse und fertig...
Außerdem sollte mein Funktionsaufruf auch gehen.
Camera ist eine abstrakte Basisklasse.

Momentan wird das kameraHandle so typisiert:

Code: Alles auswählen

class Kamera1 : public Camera<int> {
}
Aber das ist ja nicht das Problem.

Verfasst: 21. April 2010 15:37
von franzf
hmroessler hat geschrieben:@franzf
Wenn es dann jetzt WIRKLICH eine template-basierte Lösung sein MUSS, kann man einfach mal einen Blick in boost::any werfen. Ist nicht wirklich viel zu Lesen und zu Verstehen
Vielleicht wäre das ein Weg. Aber diesen würde ich nur sehr ungerne gehen, da ich wirklich nur externe Libs einbinden will, wenn es absolut nicht anders geht.
Boost.Any bringt dir absolut nichts für dein Problem! Ich habe nur gesagt du sollst einen Blick darauf werfen, sprich die Sourcen anschauen! boost::any ist sowas wie QVariant, nur eben templatebasiert. DU kannst ein boost-any-Objekt aber OHNE konkretem Template-Parameter anlegen. Später wird dein any-Objekt aber mit x-beliebigen Typen gefüllt. Genau das was du ERREICHEN willst ;)

Trotzdem ist hier, wie Christian schon sagte, kein template nötig:

Code: Alles auswählen

class Camera {
 // Basisklasse, mit allen nötigen Funktionen
 // Kapselt Zugriffe auf ein beliebiges HANDLE.
 // Bietet nur ein abstraktes Interface, um typenunabhängig mit der Kamera zu kommunizieren
};

class CameraA : public Camera {
    CamerHandleA handle;
    // virtuelle Funktionen aus Camera implementieren
};

class CameraB : public Camera {
    CameraHandleB handle;
    // virtuelle FUnktionen implementieren
};

class MainWindow : public QMainWindow {
    Camera* cam; // nur ein Basisklassenzeiger
};
Ich hoffe das ist jetzt etwas klarer.

Verfasst: 21. April 2010 15:48
von RHBaum
Aber trotzdem hat Christian recht (hat er eigentlich immer).

Templates und dynamisch haben recht wenig gemeinsam.

ein template wird vom compiler zur compilezeit typisiert. das heisst der compiler muss wissen, welchen typ das template bekommt, und zwar beim compilieren und nicht zur laufzeit (wenn dein construktor aufgerufen wird).

Und eigentlich ist es gar nicht dein problem, weil die Cameras selber hasst ja schon dynamisiert (code wiederverwendung durch unterschieben unterscheidlicher Objecte wo man erst zur laufzeit genau weiss was was ist, ist eigentlich Polymorphie in reinform, deine abstracte basisklasse ist also vollkommen richtig).

Dein eizigstes aergerniss ist noch eine variable, die zur laufzeit unterschiedliche typen (Pods / zeiger) aufnehmen muss, und evtl noch nen indikator, der dir genau sagt was da grad drinnesteht.
Und heh, genau dafuer gibt es auch was.
Man kann alle typen auf nen genuegend grossen speicherbereich plattkloppen, und wild casten (so hat mans unter C oft genug gemacht).
Eleganter und ohne casten gehen Unions ! Und das schon seit C-Zeiten !

http://www.willemer.de/informatik/cpp/union.htm

nun brauchst eigentlich nur noch nen Indikator (enum), welcher Typ grad drinne ist.

Aber da du ned der einzigste mit dem problem bist, gibts das schon fertig, und mit ner menge Hilfsfunktionen.
Die sogananten Varianten-Typen oder Kurz Variants.
Der Hinweis kam aber schon : boost::any ist ein vertreter der Gattung (falls man sowas qt-frei braucht)

Aber warum in die Ferne .....
Qt hat natuerlich auch sowas :
http://doc.qt.nokia.com/4.6/qvariant.html

Jetzt muss man das nur noch benutzen ....

@franzf
boost::any ist sowas wie QVariant, nur eben templatebasiert.
hmmm ? wo muss man boost::any typisieren ? Ueberseh ich da was ? Dacht boost::any iss eben genau ein Variant.
oder verwechsel ich da grad was mit boost::variant ???

Ciao ....

Verfasst: 21. April 2010 16:10
von franzf
RHBaum hat geschrieben:@franzf
boost::any ist sowas wie QVariant, nur eben templatebasiert.
hmmm ? wo muss man boost::any typisieren ? Ueberseh ich da was ? Dacht boost::any iss eben genau ein Variant.
oder verwechsel ich da grad was mit boost::variant ???

Code: Alles auswählen

boost::any obj;
obj = std::string("Hallo Welt!");
obj = 10;
obj = MyType(22, 33, "Peterchen");
boost::any verwendet einen templatebasierten any_holder, boost::any::any() ist nicht templatebasiert. boost::any::operator= hingegen schon.
Von der Verwendung her ist das komplett anders als boost::variant.

Ich weiß jetzt nicht, ob direkt boost::any für ihn sinnvoll ist, um seinen Handle zu speichern.
Es würde mich eh stark wundern, wenn die Funktionen, um mit der Kamera zu kommunizieren, alle exakt gleich heißen und ausschauen, damit er NUR den anderen Handle einsetzen muss und alles klappt...
Wenn aber schon, dann macht vllt. ein template wieder Sinn, sonst hätte er ja wahnsinnige Code-Duplizierung in allen Camera-Derivaten. Da könnte er auch noch mal genauer was sagen :)

[gelöst]

Verfasst: 21. April 2010 16:12
von hmroessler
Hallo RHBaum,

vielen Dank für den Hinweis mit QVariant. Ähnliches verwende ich ja bereits, indem ich in meiner "Camera" Klasse das Handle als void* speichere. Nur benötige ich in beiden Fällen casts, die ich eigentlich vermeiden wollte.

Aber gut, scheint anders wohl nicht zu gehen.

Vielen Dank an Euch (Christian81, franzf und RHBaum) für eure geduldige und kompetente Unterstützung. :D

viele Grüße
hmroessler

Verfasst: 21. April 2010 17:30
von RHBaum
Nur benötige ich in beiden Fällen casts
naja, du musst scho sehr Exotische typen verwenden, um bei QVariant casten zu muessen.
Schau dir die toXYZ() funktionen am QVariant an, da sollt was fuer Dich bei sein.

ansonsten ohne casten gehts ueber Unions immer, auch mit zeiger, wenn die adresse selber der wert sein soll.
Der compiler muss zur compilezeit den Typ nur von der groesse her bestimmen koennen, leer anlegen koennen (StdCtor) und kopieren koennen (CCTor).

Ciao ...