GCC 4.4.7 vs. GCC 4.7
-
Ja gibt es.

Storage ist eine HeterogeneousMap:
std::map<std::string, boost::any> storage;Dadurch ist set:
template<typename T> void HeterogeneousMap::set(const char * key, const T & t) { if (!storage[key].empty()) { if (storage[key].type() != typeid (T)) { std::stringstream buf; buf << "bad type, expect " << storage[key].type().name() << " for key: " << key; throw ParameterException(buf.str().c_str()); } storage[key] = t; } else { storage[key] = t; } }Ich speichere unter string Schlüssel zu verschiedene Objekte. Damit da so ne Art Typsicherheit für das intern zugreifen auf die Map.
-
Bitte compilierbares (bzw. beim GCC 4.7 bis auf den Fehler compilierbares) Minimalbeispiel erstellen und posten.
http://www.c-plusplus.net/forum/304133Die wichtige Frage, was PeerIDList ist, hast du auch noch nicht beantwortet. Die Antwort sollte sich aber aus dem Minimalbeispiel von selbst ergeben, also sieh lieber zu, dass du das Minimalbeispiel erstellst, anstatt diese Frage zu beantworten. Falls sich aus dem Minimalbeispiel nicht ergeben sollte, was PeerIDList ist, dann hast du den Fehler schon gefunden, denn dann weiss es der Compiler auch nicht*. Das ist einer der Vorteile beim Erstellen solcher Beispiele, dass man dabei meistens schon alleine den Fehler findet
.*: Warum der GCC 4.4 das dann trotzdem uebersetzt ist eine andere Frage. Ist vielleicht irgendein Include veraendert worden? Verlaesst du dich vielleicht irgendwo auf indirekte Includes der Standardheader? Waehrend die Header der Standardbibliothek des GCC 4.4 noch recht grosszuegig andere Header eingebunden haben, hat man in den letzten Jahren recht viele Anstrengungen unternommen, diese Indirektionen moeglichst raus zu machen (ausser dort, wo sie vom Sprachstandard vorgeschrieben sind). Dadurch ist eventuell irgendein Typ nicht bekannt. Aehnliches gilt eventuell auch, falls du unterschiedliche Versionen von Boost benutzt.
-
sven_ schrieb:
Dadurch ist set:
template<typename T> void HeterogeneousMap::set(const char * key, const T & t)Was du innerhalb von
settust, ist irrelevant. Wichtig ist nur die Signatur.Da dort ein
const T&vorkommt, wobeiTein Templateparameter ist, kann das Templateargument beim Aufruf hergeleitet werden. Es reicht also,storage.set("peerIDList", peerList);zu schreiben.
-
Ich vermute mal ein fehlendes template-Schlüsselwort (unterstellt, dass storage ein abhängiger Bezeichner ist). Andererseits hat gcc 4.4.7 das auch schon an solchen Stellen verlangt.
-
ich tippe auf Fehler beim includen
-
camper schrieb:
Ich vermute mal ein fehlendes template-Schlüsselwort (unterstellt, dass storage ein abhängiger Bezeichner ist).
Ja... aber
storageist, wie er direkt in seinem zweiten Post zeigt, nicht abhängig von irgendwelchen Template-Argumenten deklariert.
-
Hallo zusammen,
sorry, hab mich ne Weile nicht gemeldet, da ich beruflich unterwegs war. Hier mal ein Minibeispiel, welches den Fehler erzeugt:
#include <cstdlib> #include <string> #include <iostream> #include <map> #include <vector> #include "boost/any.hpp" typedef std::vector<int> PeerIDList; class HeterogeneousMap { public: HeterogeneousMap() { } virtual ~HeterogeneousMap() { } template<typename T> void set(const std::string & key, const T & t) { if (!storage[key].empty()) { if (storage[key].type() == typeid (T)) { std::cerr << "fehler\n"; throw 0; } storage[key] = t; } else { storage[key] = t; } } template<typename T> T get(std::string key) { if (storage[key].empty()) { return T(); } else { if (storage[key].type() == typeid (T)) { return boost::any_cast<T>(storage[key]); } else { std::cerr << "fehler\n"; throw 0; } } } private: std::map<std::string, boost::any> storage; }; class BaseTimer { protected: HeterogeneousMap storage; }; template <typename T> class ReferenceTimer : public BaseTimer { }; template <typename T> class ReferenceMonitorTimer : public ReferenceTimer<T> { public: virtual void setPeerIDList(PeerIDList peerList) { BaseTimer::storage.set("peerIDList", peerList); } virtual PeerIDList getPeerIDList() { return BaseTimer::storage.get<PeerIDList>(std::string("peerIDList")); } }; /* * */ int main(int argc, char** argv) { ReferenceMonitorTimer<int> timer; PeerIDList list1; timer.setPeerIDList(list1); PeerIDList list2 = timer.getPeerIDList(); return 0; }Als Fehler erhalte ich:
g++ -std=c++0x -c -g -s -MMD -MP -MF "build/Debug/GNU_1-Linux-x86/main.o.d" -o build/Debug/GNU_1-Linux-x86/main.o main.cc main.cc: In member function ‘virtual PeerIDList ReferenceMonitorTimer<T>::getPeerIDList()’: main.cc:91:55: error: expected primary-expression before ‘>’ token gmake[2]: *** [build/Debug/GNU_1-Linux-x86/main.o] Error 1Ich nutze um auf Centos6 eine Gcc 4.7 Umgebung zu haben die RedHat DevTools 1.1. Lasse ich im Aufruf <PeerIDList> weg, bekommt er das Template nicht mehr aufgelöst. Es sieht für mich aus, als ob er PeerIDList im Kontext nicht kennt, aber wieso????
Besten Danke für Eure Unterstützung im Vorraus.
-
template <typename T> class ReferenceMonitorTimer : public ReferenceTimer<T> { public: virtual void setPeerIDList(PeerIDList peerList) { BaseTimer::storage.set("peerIDList", peerList); } virtual PeerIDList getPeerIDList() { return BaseTimer::storage.get<PeerIDList>(std::string("peerIDList")); } };Das ist mal tricky.
BaseTimerhängt nicht von T ab. Aber die Basis vonReferenceMonitorTimer<T>istReferenceTimer<T>, was vonBaseTimererbt. Dem Compiler ist jedenfalls in der ersten Lookup-Phase nicht bekannt, dassBaseTimerwirklich eine Basisklasse vonReferenceMonitorTimer<T>ist.Probier mal das hier:
return this->storage.template get<PeerIDList>(std::string("peerIDList"));Mit
this->dürfte klar sein, dassstorageein Element einer Basis ist. Weil in der direkten BasisTauftaucht, wird das Lookup fürstorageverzögert. Weil der Compilerstoragein der ersten Lookup-Phase nicht kennt, müssen wir ihm sagen, dass es sich beigetum ein Template handelt und dass damit das<eine "spitze Template-Klammer" statt des kleiner-als-Operators ist.
-
Das ist ja mal geil. Es geht! Darf man noch fragen was storage.template ist? Kenne ich bisher nicht. Heißt es also, es ist problematisch, von templates zu erben und dann elemente der basis zu nutzen? kann man dies eventl. durch eine bessere basismethode fixen?
sven_
-
sven_ schrieb:
Das ist ja mal geil. Es geht! Darf man noch fragen was storage.template ist?
Hab ich ja versucht zu erklären.
storagewurde nicht inReferenceMonitorTimer<T>definiert. Und weil die Basis vonReferenceMonitorTimer<T>auch vonTabhängt, iststorageinthis->storageein von einem Template-Parameter abhängiger Name. Wenn der Compiler das erste mal über das Template guckt, also bevor Du es instantiierst, dann weiß er nicht, wasstorageist und dass es ein Member-Template namensgethat.getkönnte auch ein Datenelement sein, was du dann mit dem Kleiner-Als-Operator mit etwas anderes zu vergleichen versuchst. Es gibt hier also eine Mehrdeutigkeit, die manuell aufgehoben werden muss. Dazu schreibt man dann dastemplate-Schlüsselwort vor dasget. Dann weiß der Compiler, dassgetein Template ist. So etwas ähnliches kennst Du wahrscheinlich schon. Manchmal muss man an einigen Stellen eintypenameeinbauen. Z.B. hier:template<class T> class foo { vector<T> bar; void transmogrify() { typename vector<T>::iterator it = bar.begin(); // ^^^^^ } };Und so ähnlich ist das mit
templatefür Member-Templates auch.Stichwörter für Dich zum Recherchieren:
Two-Phase-Lookup
Dependent Names
-
Hallo kkaw,
das mit der stufenweisen Auflösung hab ich verstanden. Das keyword template kannte ich an der Stelle allerdings nicht. Danke für die Recherche-Tips, da werde ich nebenbei mal ein wenig die Suchmaschine bemühen.

Vielen Dank.