Template: Exception bei nicht unterstütztem Typ
-
Hallo,
ich habe eine Funktion die mir es erlaubt eine Variable vom big- zum litte endian Format zu konvertieren und andersrum.
Ich nutze dafür die entsprechenden Instruktionen. Daher existiert für jeden - möglichen - Typ eine Implementation:
template<typename operand> operand bswap( operand ) { assert(false); operand ret_val; return ret_val; #ifdef _MSC_VER #pragma message("Warning: implementation for specified operand type doesn't exist") #endif } template<> uint16 bswap(uint16 value) {return Detail::bswap_word(value);} template<> uint16& bswap(uint16& value) {return Detail::bswap_word_ref(value);} template<> uint32 bswap(uint32 value) {return Detail::bswap_dword(value);} template<> uint32& bswap(uint32& value) {return Detail::bswap_dword_ref(value);} template<> uint64 bswap(uint64 value) {return Detail::bswap_qword(value);} template<> uint64& bswap(uint64& value) {return Detail::bswap_qword_ref(value);}Ist die non-specialized template Funktion - die bei allen anderen Typen aufgerufen wird - so in Ordnung oder sollte man das anders machen?
-
#ifdef _MSC_VER #pragma message("Warning: implementation for specified operand type doesn't exist") #endifsollte immer ausgelöst werden.. woher soll denn der präprozessor wissen, ob das template instantiiert wird oder nicht? er sieht es -> er warnt!
bb
edit:
ich würds so machen:template<typename T> T endian_swap(T val); //LNK-error template<> T endian_swap<short>(short val) { return detail::short_swap(val); }
-
unskilled schrieb:
#ifdef _MSC_VER #pragma message("Warning: implementation for specified operand type doesn't exist") #endifsollte immer ausgelöst werden.. woher soll denn der präprozessor wissen, ob das template instantiiert wird oder nicht? er sieht es -> er warnt!
bb
Nein, mit Sicherheit nicht.
Es wird nur ausgelöst, wenn eine unspecialized operand type Variante instantiiert (verwendet) wird.Es ist ja der Sinn eines Templates, dass erst zur Kompilierzeit die eigentliche Klasse / Struct / Funktion angelegt wird.
Soll heißen: Bevor man (z.B.) bswap<double> nicht verwendet existiert es auch nicht.
-
unskilled schrieb:
ich würds so machen: [cpp] template<typename T> T endian_swap(T val); //LNK-error template<> T endian_swap<short>(short val) { return detail::short_swap(val); }Ja, stimmt schon. Ist zwar die Primitivste, aber eine definitiv funktionierende Lösung.
Ich dachte nur, es wäre schön, etwas mehr Feedback zu geben. Ist zwar im Endeffekt von vornherein Quatsch bswap für etwas anderes zu benutzten, aber man weiß ja nie
Dachte es gibt vielleicht die Möglichkeit - jetzt MSC spezifisch - eine echte Warnung auszugeben.
Der per message() erscheinende Text ist da nicht wirklich nützlich, da das im Output-Fenster sowie jeder übersieht.
-
FrEEzE2046 schrieb:
Nein, mit Sicherheit nicht.
Doch. Der Präprozessor funktioniert ganz anders als du dir das offenbar vorstellst. Du kannst aber Compilezeitassertions mit Meldungen machen, guck die mal die Boost Metaprogrammierungsbibliotheken an, die müssten sowas haben.
-
SeppJ schrieb:
Doch. Der Präprozessor funktioniert ganz anders als du dir das offenbar vorstellst. Du kannst aber Compilezeitassertions mit Meldungen machen, guck die mal die Boost Metaprogrammierungsbibliotheken an, die müssten sowas haben.
Ich würd's ja gerne glauben, aber warum funktioniert es dann?!
Verwende ich im Code:
bswap<double>(8.0);kommt meine Meldung. Kommentiere ich es aus, dann nicht. Also genau das was ich wollte ...
Ich bin mir durchaus im klaren darüber, wie der Präprozessor funktioniert. Ich gehe sogar fest davon aus, dass selbige Deklaration mit gcc nicht funktionieren würde (sehen wir mal von der sowieso nicht vorhanden Direktive ab).
Mir ist klar, dass das mal wieder eine MSC-only Geschichte ist, aber andere Compiler grenze ich ja sowieso aus.
-
hmm.. also zumindest der msvc scheint sich da nicht ganz korrekt zu verhalten:
template<typename T> void t(T) { # pragma message("hi") } template<> void t(int) {} int main() { ; //keine msg // t(int()); //keine msg // t(float()); //msg }sehr eigenartig...
aber imho definitiv nicht standard-konform...bb
-
unskilled schrieb:
sehr eigenartig...
aber imho definitiv nicht standard-konform...
bbSag ich doch

Was ist beim MSC schon wirklich Standard? Alles andere hab ich ja auch ausgeschaltet, aber wenn es statt message kein warning Pendandt gibt, ist die Lösung das Ding einfach nicht zu definieren und den Linker die Arbeit machen zu lassen, wohl am einfachsten.
-
schau mal nach boost::enable_if und ähnlichem. Das könnte auch helfen.
-
also ehrlich ich verstehe das problem nicht.
wenn man die default-implementierung weglässt, wird ein compiler-FEHLER erzeugt. besser geht's ja wohl nicht.wieso sollte man jetzt krampfhaft versuchen dieses verhalten zu verschlechtern, indem man aus dem FEHLER einen leicht zu übersehenden hinweis macht?!?
BTW: jeder C++ programmierer mit ein wenig erfahrung wird sofort verstehen was es bedeutet, wenn der compiler hier rumsudert dass er das template nicht instanzieren kann. die verständlichkeit ist IMO also auch kein argument.
-
hustbaer schrieb:
wenn man die default-implementierung weglässt, wird ein compiler-FEHLER erzeugt. besser geht's ja wohl nicht.
Wie machst du das? Ich bekomm nur nen Linkererror.
-
Das Template undefiniert zu lassen führt - wenn es verwendet wird - im günstigsten Fall zu einem Linkerfehler, weil keine Instantiierung stattgefunden hat (die Suche nach Fehlerstelle dauert dann ein paar Stunden).
Ein assert/abort o.ä. führt erst zum Abbruch bei der Programmausführung (der Fehler wird dann irgendwann zuerst durch den Kunden entdeckt, bzw. gar nicht, weil keine Debugbuilds ausgeliefert werden).
Wird die Menge der möglichen Templateargumente per SFINAE ausreichend eingeschränkt, erhält man sofort beim Compilieren eine Diagnose, die allerdings jenach Compiler irreführend sein kann - zudem zudem führt es zu Duplizität im Code, weil die Typen, für die spezialisiert wird, vorweggenommen werden.
Ist der Code des Templates derart, dass eine Instantiierung nicht möglich ist, tritt der Fehler ebenfalls beim Compilieren auf und man hat die möglichkeit, mit ein bisschen Compiler-Magie die Fehlermeldung lesbar zu gestalten.template<typename T> T endian_swap(T val) { BOOST_STATIC_ASSERT( false && "not implemented for this type" ); }
-
OK, dann Linker-Fehler.
Auf jeden Fall besser als eine einfache Meldung + Programm compiliert + linkt + baut dann aber scheisse wenn man es startet.static_assert() ist natürlich auch eine Möglichkeit.