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