2016-06-13 2 views
1

Anwendungsfall: ein Puffer von Datensätzen. Hier ist die Grundidee. Damit es funktioniert, muss der Konstruktor der Datensatzstruktur den Schlüssel kennen, der als Datensatznummer verwendet wird, wenn ein Element zur Karte hinzugefügt wird. Natürlich kann dies mit mehr Code gemacht werden, aber das sieht mir sehr elegant aus. Minimal codiert:Zugriffsschlüssel im Konstruktor der Struktur in einer Karte

#include <whatever> 
struct record 
{ 
    string foo; 
    record(unsigned irec) { foo=readrecord(irec); } 
}; 

map<unsigned,record>recbuf; 

int main() 
{ 
    // if the element is not yet in the map, it should be read. 
    string foo_ten=recbuf[10].foo; 
    // do something with the result 
    printf("foo_ten: %s\n",foo_ten.c_str()); 
    return 0; 
} 

Edit1: Code oben wird nicht funktionieren. Irgendwelche Ideen, wie man das zur Arbeit bringt? Edit2: I abgeleitet eine MapPlus Klasse das Hinzufügen eines weiteren Karte :: operator []:

template<class _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty> > >class mapplus :public map<_Kty, _Ty, _Pr, _Alloc> 
{ 
public: 
    mapped_type& operator[](const _Kty &_Keyval) 
    { // find element matching _Keyval or insert with default mapped 
     iterator _Where = _Mybase::lower_bound(_Keyval); 
     if (_Where == _Mybase::end() 
      || _Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode()))) 

      _Where = _Mybase::emplace_hint(_Where, 
       _Keyval, 
       _Ty(_Keyval)); 
     return (_Where->second); 
    } 
}; 

Dies funktioniert. Ich bin immer noch an Kommentaren interessiert, die mich darauf hinweisen, dass ich das unnötig unnötig gemacht habe. Habe ich? Kann es mit weniger Aufwand gemacht werden?

+1

Was genau ist Ihre Frage? Funktioniert es sogar ohne Standardkonstruktor? –

Antwort

0

Sie möchten also record Objekte mit Ihrem record(unsigned) Konstruktor anstelle des Standardkonstruktors erstellt werden.

Leider gibt es keine Möglichkeit, dies zu tun mit operator[] (reference):

Wenn k den Schlüssel eines Elements in dem Behälter übereinstimmt, wird die Funktion einen Verweis auf seine abgebildet Wert zurückgibt.

Wenn k nicht mit dem Schlüssel eines Elements im Container übereinstimmt, fügt die Funktion ein neues Element mit diesem Schlüssel ein und gibt einen Verweis auf den zugeordneten Wert zurück. Beachten Sie, dass dadurch der Container immer um eins vergrößert wird, auch wenn dem Element kein zugewiesener Wert zugewiesen ist (das Element wird mit seinem Standardkonstruktor erstellt). es scheint wie ein schlechtes Design

würde ich nicht empfehlen operator[] für std::map, für mich zu überlasten.

Sie können es jedoch mit anderen Methoden wie insert oder emplace (C++ 11) tun. Siehe zum Beispiel, diese Antwort mit: Using std::map<K,V> where V has no usable default constructor

Getestet Beispiel:

#include <map> 
#include <sstream> 
#include <iostream> 


std::string readRecord(int id) 
{ 
    std::stringstream stream; 
    stream << id; 
    return stream.str(); 
} 

struct Record 
{ 
    Record(int id) 
     : foo(readRecord(id)) 
    { 
    } 

    std::string foo; 
}; 

int main() 
{ 
    std::map<int, Record> m; 
    for (int i = 0; i < 10; ++i) 
     m.insert(std::make_pair(i, Record(i))); 

    std::cout << m.at(5).foo << std::endl; 
    // std::cout << m[7].foo << std::endl; // error 'Record::Record': no appropriate default constructor available 

    return 0; 
} 
+0

Danke, dass Sie auf die frühere Diskussion hingewiesen haben. Es ist nützlich - und hat einen Vorschlag dafür, ziemlich genau das zu tun, was ich getan habe, und Verweise auf Boost, die nützlich sein werden. Ich werde sehen, ob ich das Problem des "schlechten Designs" "lösen" kann, indem ich es spezifischer mache, z. Nur ganzzahlige Schlüssel. Imo ist das ausreichend einfach, um eine Lösung zu haben, die auch eine eckige Klammerreferenz erlaubt. – Jan

+0

@Jan, seien Sie sich dessen bewusst, dass andere Programmierer möglicherweise von nicht standardmäßigen STL-Container-Semantiken in Ihrem Programm/Ihrer Bibliothek überrascht werden, was gegen https://en.wikipedia.org/wiki/Principle_of_least_astonishment verstößt. Ich urteile nicht oder so, sage nur meine persönliche Meinung :) –

Verwandte Themen