Template-Verwirrung
Verfasst: 08.10.2013, 20:17
Hallo zusammen,
ich hätte hier mal wieder ein etwas spezielles Problem in C++, auf das mir mangels Erfahrung mit Templates gerade keine schöne Lösung einfallen mag.
Gegeben sei:
Analog zu Inject1 gibt es noch N weitere; und analog zu WorkA gibt es noch X weitere. Jedes konkrete WorkX benötigt ein spezielles InjectN.
Alle WorkX werden an einer Stelle anhand eines von außen gegebenen Parameters erzeugt:
Diesen Switch finde ich aber hässlich:
Dann habe ich ein Funktionstemplate gebaut:
Ebenfalls Punkt1 gelöst, und das Makro ist weg. Die Lösung von Punkt 2 ist näher, da ich jetzt etwas habe, was eine Adresse besitzt. Aber so richtig verwenden kann ichs nicht.
Dafür muss ich jetzt wieder den Typnamen wiederholen, weil der Compiler nur den expliziten Template-Aufruf hinbekommt. Im impliziten Fall kann er den Typ T nicht deduzieren. Wieso eigentlich? Promoted der enum zu einem int, und es wird nach einer Klasse gesucht, die irgendwas int-kompatibles als nested Type enthält? Und wie muss ich das Template denn aufbohren, damit ich es implizit (create(WorkA::MODE1)) aufrufen kann? Geht das überhaupt? Anscheinend ist WorkA::MODE1 nicht eindeutig genug, um zu erkennen, dass T WorkA sein muss?
Und die andere Frage: Kann ich diese Template-Funktionen so bauen, dass ich sie ganz generisch über einen Pointer aufrufen kann? Also soetwas in der Art:
Sorry, wenn das jetzt etwas wirr aussieht. Aber eventuell kennt jemand eine schöne Lösung dafür?
ich hätte hier mal wieder ein etwas spezielles Problem in C++, auf das mir mangels Erfahrung mit Templates gerade keine schöne Lösung einfallen mag.
Gegeben sei:
Code: Alles auswählen
class InjectInterface { ... };
class Inject1: public InjectInterface {};
class WorkInterface { ... };
class WorkA: public WorkInterface
{
typedef enum {MODE_1, MODE_2, ... , MODE_N} mode_t;
typedef Inject1 inject_t; // 1..n möglich
WorkA(mode_t mode, inject_t *inject) { ... };
};
Alle WorkX werden an einer Stelle anhand eines von außen gegebenen Parameters erzeugt:
Code: Alles auswählen
InjectInterface *i;
WorkInterface *w;
switch (outerParameter)
{
case MAGIC_VALUE_1: i = WorkA::inject_t(); w = new WorkA(MODE_1, i); break;
case MAGIC_VALUE_2: i = WorkA::inject_t(); w = new WorkA(MODE_2, i); break;
... // alle möglichen Instantiierungen von WorkX mit verschiedenen InjectN
}
- Weil ich mir mit redundantem Sch... die Finger wundtippe.
- Weil ich an anderer Stelle einen ähnlichen Switch habe, der mir für jeden MAGIG_VALUE sagt, ob dazu ein WorkX/InjectN-Paar gebaut werden kann. Schöner wäre ein Switch, der mir Funktionszeiger auf etwas gibt, mit dem ich das WorkX/InjectN-Paar bauen kann. Den kann ich dann sowohl zur Existenzbestimmung als auch zur Erzeugung nutzen.
Dann habe ich ein Funktionstemplate gebaut:
Code: Alles auswählen
template<T> void create(T::mode_t mode)
{
i = new T::inject_t();
w = new T(mode, static_cast<T::inject_t*>(i));
}
// Verwendung:
switch (outerParameter)
{
case MAGIC_VALUE_1: create<WorkA>(WorkA::MODE1); break;
...
}
Dafür muss ich jetzt wieder den Typnamen wiederholen, weil der Compiler nur den expliziten Template-Aufruf hinbekommt. Im impliziten Fall kann er den Typ T nicht deduzieren. Wieso eigentlich? Promoted der enum zu einem int, und es wird nach einer Klasse gesucht, die irgendwas int-kompatibles als nested Type enthält? Und wie muss ich das Template denn aufbohren, damit ich es implizit (create(WorkA::MODE1)) aufrufen kann? Geht das überhaupt? Anscheinend ist WorkA::MODE1 nicht eindeutig genug, um zu erkennen, dass T WorkA sein muss?
Und die andere Frage: Kann ich diese Template-Funktionen so bauen, dass ich sie ganz generisch über einen Pointer aufrufen kann? Also soetwas in der Art:
Code: Alles auswählen
CreationFunc* getCreator(magic_value_t t)
{
switch (t)
{
case MAGIC_VALUE_1: return &(someTemplateFunc<WorkA::MODE1>);
...
}
}
// Aufruf:
CreationFunc* f = getCreator(MAGIC_VALUE_1);
f(); // i und w sind jetzt mit Zeigern auf gültige Instanzen gefüllt
bool canCreate = (NULL != getCreator(MAGIC_VALUE_1)); // Existenzüberprüfung