"We are back" « oc.at

c++: virtual template workaround

wergor 09.03.2017 - 19:10 3459 3
Posts

wergor

connoisseur de mimi
Avatar
Registered: Jul 2005
Location: vulkanland
Posts: 4113
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?
Code: CPP
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
Registered: Jan 2003
Location: Wien
Posts: 5833
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

Code: CPP
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. :p

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25517
Ja, das geht leider nicht. Der Grund dafür ist:

Zitat
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 Guide

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.

wergor

connoisseur de mimi
Avatar
Registered: Jul 2005
Location: vulkanland
Posts: 4113
Zitat von Vinci
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.

Zitat von Vinci
Eine Möglichkeit wäre wohl, dem CommandInterface einen Template Parameter für die tatsächliche Implementierung aufzudrücken. Sowas wie

Code: CPP
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.
Zitat von Vinci
Ich persönlich würde übrigens das CommandInterface nicht mit der Schnittstelle in Verbindung bringen, schon gar nicht via Vererbung. :p
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

Zitat von mat
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
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz