Fragensteller
Problem mit std::map<const ...., ....>

Frage
-
Hallo!
Ich sitze gerade vor einem Problem:
struct ltUnitType { bool operator()(const IUnit* u1, const IUnit*u2) const { return strcmp(u1->getUnitType(), u2->getUnitType()) < 0; } };
typedef std::map<const RankedCombat::IUnit*, unsigned, ltUnitType> count_map_t; count_map_t count_map; for(auto unit:units) { count_map_t::iterator i = count_map.find(unit); (*i).second; // <- schon DAS schmeisst einen Error if(i == count_map.end()) { count_map[unit] = 1; } else { ++count_map[unit]; } }
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\utility(114): error C2166: L-Wert gibt ein const-Objekt an 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\utility(113): Bei der Kompilierung der Klassen-template der std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(const std::pair<_Ty1,_Ty2> &)-Memberfunktion 1> with 1> [ 1> _Ty1=const RankedCombat::IUnit *const , 1> _Ty2=unsigned int 1> ] 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(2646): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(const std::pair<_Ty1,_Ty2> &)". 1> with 1> [ 1> _Ty1=const RankedCombat::IUnit *const , 1> _Ty2=unsigned int 1> ] 1> c:\data\projects\darkorb\libgexpgui\systemfleet.cpp(71): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "std::pair<_Ty1,_Ty2>". 1> with 1> [ 1> _Ty1=const RankedCombat::IUnit *const , 1> _Ty2=unsigned int 1> ]
Ich kann nur mit den Achseln zucken. Jedenfalls mal nachgeschlagen: Da scheinen die Fehlermeldungen zu spinnen oder der Kompiler den Geist aufzugeben. Auf den zitierten Block folgt noch etwas - wenn man das auskommentiert kompiliert der Block problemlos. Schon beim ersten Durchblättern der Fehler wird's komisch. Da:
template<class _FwdIt, class _Ty> inline void _Fill(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // copy _Val through [_First, _Last) for (; _First != _Last; ++_First) *_First = _Val; }
werde ich hingeschickt. Sollte durch die Zeile nie und nimmer aufgerufen werden, denke ich.
Mfg
Heiko
Alle Antworten
-
Hi, Martin!
Ich sag ja: das scheint am Kontext zu liegen. Ist mir echt schleierhaft. Kann das Problem beliebig reproduzieren in dem Projekt. Weiter ginge es mit
struct ltExpForKill { bool operator()(const count_map_t::value_type& u1, const count_map_t::value_type& u2) const { return u1.first->getExperienceForKill() < u2.first->getExperienceForKill(); } }; typedef std::vector<count_map_t::value_type> sorted_t; sorted_t sortedUnits; sortedUnits.reserve(count_map.size()); for(count_map_t::iterator i = count_map.begin(); i != count_map.end(); ++i) { auto k = std::lower_bound(sortedUnits.begin(), sortedUnits.end(), *i, ltExpForKill()); sortedUnits.insert(k, *i); }
Wenn ich den Block auskommentiere, funktioniert es. Wenn ich ihn drin lasse schmeisst es den Fehler im oberen Block. -
Im ganzen nochmal
typedef std::map<const RankedCombat::IUnit*, unsigned, SortingPredicates::ltUnitType> count_map_t; count_map_t count_map; for(auto unit:units) { count_map_t::iterator i = count_map.find(unit); if(i == count_map.end()) { count_map[unit] = 1; } else { ++i->second; /************** Error(see below) ***************/ } } struct ltExpForKill { bool operator()(const count_map_t::value_type& u1, const count_map_t::value_type& u2) const { return u1.first->getExperienceForKill() < u2.first->getExperienceForKill(); } }; /***************** If using this block to sort the units the error is generated typedef std::vector<count_map_t::value_type> sorted_t; sorted_t sortedUnits; sortedUnits.reserve(count_map.size()); for(count_map_t::iterator i = count_map.begin(); i != count_map.end(); ++i) { auto k = std::lower_bound(sortedUnits.begin(), sortedUnits.end(), *i, ltExpForKill()); sortedUnits.insert(k, *i); } /*******************************************/ /********** Using this works ******/ typedef std::multiset<count_map_t::value_type, ltExpForKill> sorted_t; sorted_t sortedUnits; sortedUnits.insert(count_map.begin(), count_map.end()); /*********************************/ for(sorted_t::iterator i = sortedUnits.begin(); i != sortedUnits.end(); ++i) { auto unit = (*i).first; const unsigned count = i->second; SystemFleetUnitPanel *panel = new SystemFleetUnitPanel(i->first, m_FleetUnits, i->second); m_UnitPanels.push_back(panel); if(i->second <= 1) { panel->setSliderColor(m_UnitsColor); } }
-
Hallo,
Ihr Problem ist, dass value_type aus der Map, den Schlüsselwert konstant setzt. Das ergibt auch Sinn, denn die Werte der Schlüssel sollen nicht geändert werden, nachdem sie in die Map eingetragen wurden. Das heißt für Sie, dass Sie alle count_map_t::value_type durch std::pair<const IUnit*, unsigned> ersetzen müssen.
Viele Grüße
App-Entwickler-Hotline für MSDN Online Deutschland
Disclaimer:
Bitte haben Sie Verständnis dafür, dass wir hier auf Rückfragen gar nicht oder nur sehr zeitverzögert antworten können.
Bitte nutzen Sie für Rückfragen oder neue Fragen den telefonischen Weg über die App-Entwickler-Hotline: http://www.msdn-online.de/Hotline
Es gelten für die App-Entwickler-Hotline und dieses Posting diese Nutzungsbedingungen , Hinweise zu Markenzeichen, Informationen zur Datensicherheitsowie die gesonderten Nutzungsbedingungen für die App-Entwickler-Hotline. -
Das ist eigentlich kein Problem. Die Funktionen von IUnit, die benutzt werden, sind alle const. Sonst würde ja auch der 2. Block nicht kompilieren. Da muss irgendetwas anderes falsch sein.
Die Zeile, an welcher der Fehler gemeldet wird, sollte nie und nimmer irgendeine Container-Funktion aufrufen. Aber dahin verweist die Fehlerausgabe. _Fill(....) wird glaube ich benutzt, um einen Container mit einem bestimmten Wert zu initialisieren.
__
PS: Entschuldigung. Ich beginne gerade zu verstehen. Der Typ des 1. Paar-Feldes ist "const IUnit* const" aufgrund des konstanten Schlüsselwertes. Das ändert hier aber trotzdem nichts, weil das Feld nirgendwo verändert wird, es sei denn vector<>::insert benutzt den =-Operator. Ob das so ist und sein muss, müsste ich noch nachschlagen. Der gemeldete Fehler jedenfalls macht trotzdem keinen Sinn.
- Bearbeitet Heiko Lewin Dienstag, 15. Juli 2014 10:37
-
Hallo,count_map_t::value_type ist vom Typ std::pair<IUnit const* const, unsigned int>. Das bedeutet, dass first ein konstanter Zeiger auf ein konstantes Objekt ist. Sie können also weder das Objekt auf das der Zeiger zeigt ändern, noch den Zeiger im Pair selber! Nun muss std::vector::insert aber unter Umständen seine Elemente verschieben, kann das aber nicht, weil first aus dem Pair nicht überschrieben werden darf (weil es const ist).
Viele Grüße
App-Entwickler-Hotline für MSDN Online Deutschland
Disclaimer:
Bitte haben Sie Verständnis dafür, dass wir hier auf Rückfragen gar nicht oder nur sehr zeitverzögert antworten können.
Bitte nutzen Sie für Rückfragen oder neue Fragen den telefonischen Weg über die App-Entwickler-Hotline: http://www.msdn-online.de/Hotline
Es gelten für die App-Entwickler-Hotline und dieses Posting diese Nutzungsbedingungen , Hinweise zu Markenzeichen, Informationen zur Datensicherheitsowie die gesonderten Nutzungsbedingungen für die App-Entwickler-Hotline. -
Also ich hab mal kurz ein Proposal für die move-semantics überflogen und einen kleinen Test gemacht.
struct tst_t { const int a; tst_t() : a(1) {} }; std::vector<const tst_t> tst; tst.push_back(tst_t()); tst.insert(tst.begin(), tst_t());
generiert einen Fehler aufgrund der move-semantics. Dabei ist der vector explizit aus "const tst_t" zusammengesetzt. Für das insert sollte, denke ich, in dem Fall sowieso der Kopienkonstruktor verwendet werden.Ich bin mir fast sicher, dass das mit einer STL von vor 3 Jahren Problemlos kompiliert hätte, kann das aber leider nicht nachprüfen.
-
Eine Frage noch aus Interesse nach Lesen des C++ 11-Standards: das pair ist mit einem konstanten Member ja so offenbar nicht mehr MoveAssignable. Wird das noch geändert werden?
- Bearbeitet Heiko Lewin Mittwoch, 16. Juli 2014 18:56