c++: virtual template workaround
wergor 09.03.2017 - 19:10 3459 3
wergor
connoisseur de mimi
|
mein arduino kann kommandos über verschiedene schnittstellen empfangen (serial, ethernet, wlan, ...), die (bisher voneinander getrennten) klassen dafür würde ich gerne unter einer base class versammeln. in den derived classes wird es function templates geben, die in allen gleich heißen und existieren müssen und die ich deshalb gerne in der base class repräsentiert hätte (z.b. als pure virtual functions). leider erlaubt c++ keine virtual templates. hat jemand eine idee wie ich das (oder etwas vergleichbares) machen könnte? class CommandInterface
{
public:
CommandInterface();
virtual ~CommandInterface();
virtual template <class T> size_t print(T& message) = 0; //geht leider nicht :(
virtual template <class T> size_t println(T& message) = 0;
};
class CommandInterfaceSerial :
public CommandInterface
{
public:
CommandInterfaceSerial();
~CommandInterfaceSerial();
template <class T> size_t print(T& message)
{
return Serial.print(message);
}
template <class T> size_t println(T& message)
{
return Serial.println(message);
}
};
|
Vinci
hatin' on summer
|
Kannst du ein paar Beispiele für die Template Parameter nennen, die man in print und println reinschmeißen würde? Grad in einem vorab definierten Protokoll würde ich eigentlich davon ausgehn, dass diese von gleichem oder ähnlichen Typ sein müssen? Eine Möglichkeit wäre wohl, dem CommandInterface einen Template Parameter für die tatsächliche Implementierung aufzudrücken. Sowas wie template<typename Implementation>
class CommandInterface
{
template<typename T>
size_t print(T& msg) { impl.print(T); } // ev. std::forward...
private:
Implementation impl;
}
Schön is das imho nicht. Ich persönlich würde übrigens das CommandInterface nicht mit der Schnittstelle in Verbindung bringen, schon gar nicht via Vererbung.
|
mat
AdministratorLegends never die
|
Ja, das geht leider nicht. Der Grund dafür ist: Member function templates cannot be declared virtual. This constraint is imposed because the usual implementation of the virtual function call mechanism uses a fixed-size table with one entry per virtual function. However, the number of instantiations of a member function template is not fixed until the entire program has been translated. Hence, supporting virtual member function templates would require support for a whole new kind of mechanism in C++ compilers and linkers. In contrast, the ordinary members of class templates can be virtual because their number is fixed when a class is instantiated. Quelle: C++ Templates: The Complete GuideEine akzeptable Alternative, um dieses Problem zu umgehen, ist Type Erasure. Die bekannteste Implementierung davon ist boost::any. Die Template-Funktionen bleiben dann nur in der Basis-Klasse während zusätzliche Funktionen für den Aufruf von außen zur Verfügung stehen und den Typ boost::any entgegen nehmen.
|
wergor
connoisseur de mimi
|
Kannst du ein paar Beispiele für die Template Parameter nennen, die man in print und println reinschmeißen würde? Grad in einem vorab definierten Protokoll würde ich eigentlich davon ausgehn, dass diese von gleichem oder ähnlichen Typ sein müssen? byte, char, int (8,16,32 bit, signed & unsigned), float, String. Eine Möglichkeit wäre wohl, dem CommandInterface einen Template Parameter für die tatsächliche Implementierung aufzudrücken. Sowas wie
template<typename Implementation>
class CommandInterface
{
template<typename T>
size_t print(T& msg) { impl.print(T); } // ev. std::forward...
private:
Implementation impl;
}
Schön is das imho nicht. damit habe ich noch nie gearbeitet, ich schaue mir das noch an. Ich persönlich würde übrigens das CommandInterface nicht mit der Schnittstelle in Verbindung bringen, schon gar nicht via Vererbung. ![:p](/images/smilies/tongue.gif) moment, nochmal für freizeit- c++ler bitte. die von CommandInterface abgeleiteten klassen sind wrapper für die verschiedenen schnittschnellen, die über ein gemeinsames interface genutzt werden können sollen... ich stehe gerade auf der leitung ![:D](/images/smilies/biggrin.gif) Eine akzeptable Alternative, um dieses Problem zu umgehen, ist Type Erasure. Die bekannteste Implementierung davon ist boost::any. Die Template-Funktionen bleiben dann nur in der Basis-Klasse während zusätzliche Funktionen für den Aufruf von außen zur Verfügung stehen und den Typ boost::any entgegen nehmen. auf bost würde ich gerne verzichten, wäre imho overkill. müsste ich für type erasure nicht alle datentypen wrappen? ( https://en.wikibooks.org/wiki/More_...ms/Type_Erasure ) ich könnte natürlich in den sauren apfel beissen und für alle möglichen typen funktionen definieren, ich würde das aber gerne effizienter lösen.
Bearbeitet von wergor am 10.03.2017, 11:20
|