Je me dirige vers C ++ 11 à partir de C ++ 98 et je me suis familiarisé avec le mot-clé auto
. Je me demandais pourquoi nous devons déclarer explicitement auto
si le compilateur est capable de déduire automatiquement le type. Je sais que C ++ est un langage fortement typé et c'est une règle mais n'était-il pas possible d'obtenir le même résultat sans déclarer explicitement une variable auto
?
Réponses
Trop de publicités?Votre question permet deux interprétations:
- Pourquoi avons-nous besoin de "auto" à tous? Ne pouvons-nous pas tout simplement laisser tomber?
- Pourquoi sommes-nous obligés d'utiliser l'auto? Ne peut-on pas avoir implicite, si il n'est pas donné?
Bethsabée répondu gentiment la première interprétation, pour le second, de considérer les éléments suivants (en supposant qu'aucun autre des déclarations existent à ce jour; à titre d'hypothèse valide en C++):
int f();
double g();
n = f(); // declares a new variable, type is int;
d = g(); // another new variable, type is double
if(n == d)
{
n = 7; // reassigns n
auto d = 2.0; // new d, shadowing the outer one
}
Il serait possible, d'autres langues sortir assez bien avec (ainsi, mis à part le problème de l'occultation peut-être)... C'est pas le cas en C++, cependant, et la question (dans le sens de la deuxième interprétation) maintenant est: Pourquoi?
Cette fois, la réponse n'est pas aussi évidente que dans la première interprétation. Une chose est pourtant évident: L'obligation explicite pour le mot-clé qui rend la langue plus sûr (je ne sais pas si c'est ce qui a poussé le comité des langues à sa décision, il reste un point):
grummel = f();
// ...
if(true)
{
brummel = f();
//^ uh, oh, a typo...
}
Pouvons-nous d'accord sur ce de ne pas avoir besoin de plus d'explications?
Le danger encore plus grand en ne nécessitant pas d'auto, [cependant], c'est que cela signifie que l'ajout d'une variable globale dans un endroit loin d'une fonction (par exemple dans un fichier d'en-tête) peut transformer ce qui était prévu à la déclaration d'un local d'étendue variable en fonction dans une affectation à la variable globale... avec des effets potentiellement désastreux (et certainement très déroutant) de conséquences.
(cité psmears' commentaire en raison de son importance - merci pour l'allusion à l')
n'était-il pas possible d'obtenir le même résultat sans déclarer explicitement une variable
auto
?Je vais reformuler votre question légèrement de façon à vous aider à comprendre pourquoi vous avez besoin d'
auto
:N'était-il pas possible d'obtenir le même résultat sans explicitement à l'aide d'un type d'espace réservé?
N'était-il pas possible? Bien sûr, il était "possible". La question est de savoir si il vaudrait la peine de l'effort de le faire.
La plupart des syntaxes dans d'autres langues qui ne sont pas typenames de travail dans l'une des deux façons. Il y a l'Aller comme, où
name := value;
déclare une variable. Et il y a le Python de façon semblable, où l'name = value;
déclare une nouvelle variable s'name
n'a pas déjà été déclarée.Supposons qu'il n'y a pas syntaxique des problèmes avec l'application, soit de la syntaxe de C++ (même si je peux déjà voir que
identifier
suivie par:
en C++ signifie "faire une étiquette"). Alors, qu'avez-vous à perdre par rapport à des espaces réservés?Eh bien, je ne peux plus le faire:
auto &name = get<0>(some_tuple);
Voir,
auto
toujours synonyme de "valeur". Si vous souhaitez obtenir une référence, vous avez besoin pour utiliser explicitement un&
. Et il sera, à juste titre, ne parviennent pas à compiler si l'affectation d'expression est un prvalue. Ni de l'affectation à base de syntaxes a un moyen de différencier entre les références et les valeurs.Maintenant, vous pourriez faire une telle cession syntaxes déduire les références, si la valeur donnée est une référence. Mais cela voudrait dire que vous ne pouvez pas faire:
auto name = get<0>(some_tuple);
Cette copie à partir de la n-uplet, la création d'un objet indépendant de l'
some_tuple
. Parfois, c'est exactement ce que vous voulez. C'est d'autant plus utile si vous voulez vous déplacer à partir de la n-uplet avecauto name = get<0>(std::move(some_tuple));
.OK, alors peut-être que nous pourrions ajouter à ces syntaxes un peu pour tenir compte de cette distinction. Peut-être
&name := value;
ou&name = value;
signifierait pour en déduire une référence commeauto&
.OK, très bien. Ce:
decltype(auto) name = some_thing();
Oh c'est vrai, C++, en réalité, a deux espaces:
auto
etdecltype(auto)
. L'idée de base de cette déduction est qu'il fonctionne exactement comme si vous aviez faitdecltype(expr) name = expr;
. Donc, dans notre cas, sisome_thing()
est un objet, il va en déduire un objet. Sisome_thing()
est une référence, il va en déduire une référence.Ceci est très utile lorsque vous travaillez dans le code du modèle et ne savez pas exactement ce que la valeur de retour d'une fonction. Ce qui est excellent pour l'expédition, et il est un outil indispensable, même si elle n'est pas largement utilisé.
Alors maintenant, nous devons ajouter un plus à notre syntaxe.
name ::= value;
signifie "faire ce qu'decltype(auto)
n'". Je n'ai pas d'équivalent pour le Pythonic variante.En regardant cette syntaxe, n'est-ce pas plutôt facile accidentellement mis-type? Non seulement cela, il est à peine l'auto-documentation. Même si vous ne l'avez jamais vu
decltype(auto)
avant, il est grand et assez évident que vous pouvez au moins dire facilement qu'il y a quelque chose de spécial se passe. Alors que la différence visuelle entre::=
et:=
est minime.Mais que l'opinion de choses; il y a plus de questions de fond. Voyez, tout cela est basé sur l'utilisation de la syntaxe. Eh bien... que dire des endroits où vous ne pouvez pas utiliser la syntaxe? Comme ceci:
for(auto &x : container)
Nous ne changer que d'
for(&x := container)
? Parce que semble dire quelque chose de très différent de gamme à basefor
. On dirait que c'est l'initialiseur de déclaration régulièrefor
boucle, pas une gamme à basefor
. Il serait également une syntaxe différente, non déduit des cas.Aussi, la copie d'initialisation (à l'aide d'
=
) n'est pas la même chose en C++ directe d'initialisation (en utilisant le constructeur de la syntaxe). Donc,name := value;
peut ne pas fonctionner dans les cas où l'auto name(value)
aurait.Bien sûr, vous pourriez déclarer qu'
:=
sera direct-l'initialisation, mais ce serait tout à fait en harmonie avec la façon dont le reste de C++ se comporte.Aussi, il y a une chose de plus: C++14. Il nous a donné une déduction caractéristique: type de retour de la déduction. Mais cela est basé sur des espaces réservés. Comme la gamme à base
for
, il est fondamentalement basé sur un typename que renseignées par le compilateur, non par une syntaxe appliqué à un nom particulier et d'expression.Voir, tous ces problèmes proviennent de la même source: vous êtes à inventer entièrement nouvelle syntaxe pour déclarer des variables. Espace réservé à base de déclarations n'ont pas à inventer de nouvelles syntaxe. Ils sont en utilisant la même syntaxe qu'avant; ils sont juste en employant un nouveau mot-clé qui agit comme un type, mais a une signification particulière. C'est ce qui lui permet de fonctionner dans la gamme de base
for
et pour le type de retour de la déduction. C'est ce qui permet d'avoir de multiples formes (auto
vsdecltype(auto)
). Et ainsi de suite.Espaces de travail, car ils sont la solution la plus simple à ce problème, tout en conservant tous les avantages et la généralité de l'aide d'un nom de type. Si vous êtes venu avec une autre alternative qui a travaillé comme universellement comme des espaces réservés à faire, il est hautement improbable qu'il serait aussi simple que d'espaces réservés.
Sauf si c'était juste de l'orthographe des espaces réservés avec des mots clés différents ou de symboles...
En bref: auto
ont pu être classées dans certains cas, mais cela pourrait conduire à des incohérences.
Tout d'abord, comme l'a fait observer, la syntaxe de déclaration en C++ est - <type> <varname>
. Des déclarations explicites exiger un certain type ou au moins une déclaration mot-clé à sa place. Afin que nous puissions utiliser var <varname>
ou declare <varname>
ou quelque chose, mais auto
est un de longue date, mot-clé en C++, et est un bon candidat pour ce type automatique déduction mot-clé.
Est-il possible implicite de déclarer des variables par affectation, sans tout casser?
Parfois, oui. Vous ne pouvez pas effectuer d'affectation à l'extérieur de fonctions, vous pouvez utiliser l'affectation de la syntaxe pour les déclarations là. Mais une telle approche permettrait de créer des incohérences de la langue, qui peut conduire à des erreurs humaines.
a = 0; // Error. Could be parsed as auto declaration instead.
int main() {
return 0;
}
Et quand il s'agit de tout type de variables locales des déclarations explicites sont-ils de contrôler la portée d'une variable.
a = 1; // use a variable declared before or outside
auto b = 2; // declare a variable here
Si ambiguë de la syntaxe a été autorisé, de déclarer les variables globales peuvent soudainement convertir implicite locale déclarations dans les affectations. À la recherche de ces conversions nécessiterait la vérification de tout. Et pour éviter les collisions vous auriez besoin des noms uniques pour toutes les variables globales, qui détruit l'idée de la portée. Donc, c'est vraiment mauvais.
auto
est un mot-clé que vous pouvez utiliser aux endroits où vous devez normalement spécifier un type .
int x = some_function();
Peut être rendu plus générique en faisant automatiquement déduire le type int
:
auto x = some_function();
C'est donc une extension conservatrice de la langue; il s'inscrit dans la syntaxe existante. Sans cela, x = some_function()
devient une déclaration d'affectation, et non plus une déclaration.