wake-up-neo.com

Wie bekomme ich einen const_iterator mit auto?

Erste Frage: Ist es möglich, einen const_iterator mit "auto" zu erzwingen? Zum Beispiel:

map<int> usa;
//...init usa
auto city_it = usa.find("New York");

Ich möchte nur abfragen, anstatt irgendetwas zu ändern, auf das city_it gerichtet ist. Ich möchte, dass city_itmap<int>::const_iterator ist. Bei Verwendung von auto ist city_it jedoch gleich dem Rückgabetyp von map::find(), der map<int>::iterator ist. Irgendein Vorschlag?

48
virtualPN

Sorry, aber ich denke, der beste Vorschlag ist nicht mit auto, da Sie eine (implizit gültige) Typkonvertierung durchführen möchten. auto dient zum Ableiten von genauer Typ, was hier nicht gewünscht ist. 

Schreib es einfach so:

std::map<std::string, int>::const_iterator city_it = usa.find("New York");

Wie von MooingDuck richtig hervorgehoben, kann die Verwendung von Typ-Aliasnamen die Lesbarkeit und Wartbarkeit Ihres Codes verbessern:

typedef std::map<std::string, int> my_map;
my_map::const_iterator city_it = usa.find("New York");
33
Andy Prowl

Dies ist keine drastisch andere Herangehensweise an die Konvertierung in const im Vergleich zu der Antwort von @ Jollymorphic, aber ich denke, dass es nützlich ist, eine solche Einzeilerfunktion zu haben:

template<class T> T const& constant(T& v){ return v; }

Das macht die Umwandlung für das Auge viel attraktiver:

auto it = constant(usa).find("New York");
// other solutions for direct lengths comparision
std::map<std::string, int>::const_iterator city_it = usa.find("New York");
auto city_it = const_cast<const std::map<std::string, int>&>(usa).find("New York");

Nun, ich würde sagen, größer ist nicht immer besser. Sie können natürlich den Namen der Funktion nach Ihren Wünschen wählen - as_const oder nur const_ sind mögliche Alternativen.

12
Xeo

Eine andere Variante, die auto verwendet (beides ein veränderliches usa und ein const usa beibehalten):

map<std::string, int> usa;
//...init usa
const auto &const_usa = usa;
auto city_it = const_usa.find("New York");

Wenn die Karte nach init überhaupt nicht veränderbar sein muss, gibt es einige andere Optionen.

sie können usa als const definieren und mit einem Funktionsaufruf initialisieren: 

const map<std::string, int> usa = init_usa();
auto city_it = usa.find("New York");

oder ein Lambda verwenden, um eine const-Map zu initiieren:

const auto usa = [&]()->const map<std::string, int> 
   {
   map<std::string, int> usa;
   //...init usa
   return usa;
   }();
auto city_it = usa.find("New York");
6
ChetS

Eine saubere Lösung ist, mit einer const - Referenz auf die ansonsten änderbare Karte zu arbeiten:

const auto &const_usa = usa;
auto city_it = const_usa.find("New York");

Damit stellen Sie sicher, dass Sie const_usa nicht ändern können, und verwenden Iteratoren.

5
rustyx

Seit C++ 17 können Sie std::as_const wie folgt verwenden:

#include <utility>

// ...

auto city_it = std::as_const(usa).find("New York");
4
jhasse

Ich bin nicht in der Lage, dies jetzt zu testen, aber ich denke, dass es den Trick erfüllt:

auto city_it = const_cast< const map<int> & >(usa).find("New York");
1
Jollymorphic

In C++ 11 können Sie Folgendes tun:

decltype(usa)::const_iterator city_it = usa.find("New York");
0
traal