Recherche…
Remarques
Le mot clé auto
est un nom de fichier représentant un type déduit automatiquement.
C'était déjà un mot-clé réservé en C ++ 98, hérité de C. Dans les anciennes versions de C ++, il pouvait être utilisé pour indiquer explicitement qu'une variable a une durée de stockage automatique:
int main()
{
auto int i = 5; // removing auto has no effect
}
Cette ancienne signification est maintenant supprimée.
Échantillon automatique de base
Le mot auto
clé auto
fournit la déduction automatique du type d'une variable.
C'est particulièrement pratique pour traiter les noms de type long:
std::map< std::string, std::shared_ptr< Widget > > table;
// C++98
std::map< std::string, std::shared_ptr< Widget > >::iterator i = table.find( "42" );
// C++11/14/17
auto j = table.find( "42" );
avec des boucles basées sur la plage :
vector<int> v = {0, 1, 2, 3, 4, 5};
for(auto n: v)
std::cout << n << ' ';
avec lambdas :
auto f = [](){ std::cout << "lambda\n"; };
f();
pour éviter la répétition du type:
auto w = std::make_shared< Widget >();
pour éviter des copies surprenantes et inutiles:
auto myMap = std::map<int,float>();
myMap.emplace(1,3.14);
std::pair<int,float> const& firstPair2 = *myMap.begin(); // copy!
auto const& firstPair = *myMap.begin(); // no copy!
La raison de la copie est que le type renvoyé est en fait std::pair<const int,float>
!
auto et modèles d'expression
auto
peut également causer des problèmes lorsque des modèles d'expression entrent en jeu:
auto mult(int c) {
return c * std::valarray<int>{1};
}
auto v = mult(3);
std::cout << v[0]; // some value that could be, but almost certainly is not, 3.
La raison en est que l' operator*
sur valarray
vous donne un objet proxy qui fait référence à la valarray
comme moyen d'évaluation valarray
. En utilisant auto
, vous créez une référence en suspens. Au lieu de mult
avait renvoyé un std::valarray<int>
, alors le code imprimerait définitivement 3.
auto, const et références
Le mot auto
clé auto
représente lui-même un type de valeur, similaire à int
ou char
. Il peut être modifié avec le mot-clé const
et le symbole &
pour représenter respectivement un type const ou un type de référence. Ces modificateurs peuvent être combinés.
Dans cet exemple, s
est un type de valeur (son type sera infd std::string
), donc chaque itération de la boucle for
copie une chaîne du vecteur dans s
.
std::vector<std::string> strings = { "stuff", "things", "misc" };
for(auto s : strings) {
std::cout << s << std::endl;
}
Si le corps de la boucle modifie s
(comme en appelant s.append(" and stuff")
), seule cette copie sera modifiée, pas le membre d'origine des strings
.
Par contre, si s
est déclaré avec auto&
ce sera un type de référence (supposé être std::string&
), donc à chaque itération de la boucle, une référence à une chaîne dans le vecteur lui sera attribuée:
for(auto& s : strings) {
std::cout << s << std::endl;
}
Dans le corps de cette boucle, les modifications apportées à s
affecteront directement l'élément des strings
auquel il fait référence.
Enfin, si s
est déclaré const auto&
, il s'agira d'un type de référence const, ce qui signifie qu'à chaque itération de la boucle, une référence const sera affectée à une chaîne dans le vecteur:
for(const auto& s : strings) {
std::cout << s << std::endl;
}
Dans le corps de cette boucle, les s
ne peuvent pas être modifiés (c.-à-d. Qu'aucune méthode non-const ne peut y être appelée).
Lorsque vous utilisez auto
avec for
boucles basées for
plages, il est généralement recommandé d'utiliser const auto&
si le corps de la boucle ne modifie pas la structure en boucle, car cela évite les copies inutiles.
Type de retour
auto
est utilisé dans la syntaxe pour le type de retour de fin:
auto main() -> int {}
ce qui équivaut à
int main() {}
Principalement utile combiné avec decltype
pour utiliser des paramètres au lieu de std::declval<T>
:
template <typename T1, typename T2>
auto Add(const T1& lhs, const T2& rhs) -> decltype(lhs + rhs) { return lhs + rhs; }
Lambda générique (C ++ 14)
C ++ 14 permet d'utiliser auto
dans l'argument lambda
auto print = [](const auto& arg) { std::cout << arg << std::endl; };
print(42);
print("hello world");
Ce lambda est essentiellement équivalent à
struct lambda {
template <typename T>
auto operator ()(const T& arg) const {
std::cout << arg << std::endl;
}
};
et alors
lambda print;
print(42);
print("hello world");
objets auto et proxy
Parfois, l' auto
peut ne pas se comporter comme prévu par un programmeur. Il en déduit l'expression, même si la déduction de type n'est pas la bonne chose à faire.
Par exemple, lorsque des objets proxy sont utilisés dans le code:
std::vector<bool> flags{true, true, false};
auto flag = flags[0];
flags.push_back(true);
Ici, flag
ne serait pas bool
, mais std::vector<bool>::reference
, car pour la spécialisation bool
du template vector
l' operator []
renvoie un objet proxy avec l'opérateur d' operator bool
conversion operator bool
défini.
Lorsque flags.push_back(true)
modifie le conteneur, cette pseudo-référence peut se terminer par un élément qui n'existe plus.
Cela rend également la prochaine situation possible:
void foo(bool b);
std::vector<bool> getFlags();
auto flag = getFlags()[5];
foo(flag);
Le vector
est éliminé immédiatement, donc flag
est une pseudo-référence à un élément qui a été supprimé. L'appel à foo
invoque un comportement indéfini.
Dans des cas comme celui-ci, vous pouvez déclarer une variable avec auto
et l'initialiser en la convertissant au type que vous voulez déduire:
auto flag = static_cast<bool>(getFlags()[5]);
mais à ce stade, remplacer simplement auto
par bool
plus de sens.
Un autre cas où des objets proxy peuvent causer des problèmes est celui des modèles d'expression . Dans ce cas, les modèles ne sont parfois pas conçus pour durer au-delà de la pleine expression complète pour des raisons d'efficacité, et l'utilisation de l'objet proxy sur le prochain entraîne un comportement indéfini.