web-dev-qa-db-fra.com

Comment obtenir un const_iterator en utilisant auto?

Première question: est-il possible de "forcer" un const_iterator en utilisant auto? Par exemple:

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

Je veux juste interroger, au lieu de changer quoi que ce soit pointé par city_it, alors j'aimerais avoir city_it pour être map<int>::const_iterator. Mais en utilisant auto, city_it est identique au type de retour de map::find(), qui est map<int>::iterator. Toute suggestion?

48
virtualPN

Désolé, mais je pense que la meilleure suggestion est pas en utilisant auto du tout, puisque vous voulez effectuer une conversion (implicitement valide) type . auto est destiné à déduire le type exact, ce qui n’est pas ce que vous voulez ici. 

Écris-le simplement de cette façon:

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

Comme MooingDuck l'a correctement souligné, l'utilisation d'alias de type peut améliorer la lisibilité et la maintenabilité de votre code:

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

Ce n’est pas une interprétation radicalement différente de la conversion en const par rapport à la réponse de @ Jollymorphic, mais je pense qu’avoir une fonction utilitaire unique comme celle-ci est pratique:

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

Ce qui rend la conversion beaucoup plus attrayante pour les yeux:

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");

Eh bien, je dirais que plus gros n'est pas toujours meilleur. Vous pouvez bien sûr choisir le nom de la fonction selon vos préférences - as_const ou tout simplement const_ sont des alternatives possibles.

12
Xeo

Une autre variante utilisant auto (en gardant un usa mutable et un usa constant):

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

Si vous n'avez pas besoin que la carte soit modifiable du tout après init, il existe d'autres options.

vous pouvez définir usa en tant que const et l'initialiser avec un appel de fonction: 

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

ou en utilisant un lambda pour initier une carte const:

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

Une solution propre consiste à utiliser une référence const à la carte autrement modifiable:

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

Cela fera en sorte que vous ne pouvez pas modifier const_usa, et utilisera des itérateurs constants.

5
rustyx

Depuis C++ 17, vous pouvez utiliser std::as_const comme ceci:

#include <utility>

// ...

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

Je ne suis pas en mesure de tester cela pour le moment, mais je pense que ça va faire l'affaire:

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

En C++ 11, vous pouvez faire ceci:

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