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?
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");
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.
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");
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.
Depuis C++ 17, vous pouvez utiliser std::as_const
comme ceci:
#include <utility>
// ...
auto city_it = std::as_const(usa).find("New York");
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");
En C++ 11, vous pouvez faire ceci:
decltype(usa)::const_iterator city_it = usa.find("New York");