En lisant cette explication sur lvalues et rvalues, ces lignes de code m'ont traversé:
int& foo();
foo() = 42; // OK, foo() is an lvalue
Je l'ai essayé en g ++, mais le compilateur dit "référence non définie à foo ()". Si j'ajoute
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
Il compile bien, mais son exécution donne un erreur de segmentation . Juste la ligne
int& foo();
par lui-même compile et s'exécute sans aucun problème.
Que veut dire ce code? Comment attribuer une valeur à un appel de fonction et pourquoi n'est-il pas une valeur?
L'explication suppose qu'il y a une implémentation raisonnable pour foo
qui renvoie une référence lvalue à un int
valide.
Une telle implémentation pourrait être:
int a = 2; //global variable, lives until program termination
int& foo() {
return a;
}
Maintenant, puisque foo
renvoie une référence à lvalue, nous pouvons affecter quelque chose à la valeur de retour, comme ceci:
foo() = 42;
Ceci mettra à jour le global a
avec la valeur 42
, que nous pouvons vérifier en accédant directement à la variable ou en appelant foo
à nouveau:
int main() {
foo() = 42;
std::cout << a; //prints 42
std::cout << foo(); //also prints 42
}
Toutes les autres réponses déclarent un statique à l'intérieur de la fonction. Je pense que cela pourrait vous embrouiller, alors jetez un oeil à ceci:
int& highest(int & i, int & j)
{
if (i > j)
{
return i;
}
return j;
}
int main()
{
int a{ 3};
int b{ 4 };
highest(a, b) = 11;
return 0;
}
Étant donné que highest()
renvoie une référence, vous pouvez lui attribuer une valeur. Quand cela fonctionnera, b
sera changé en 11. Si vous modifiez l'initialisation de sorte que a
soit, disons, 8, alors a
sera remplacé par 11. C'est-à-dire un code qui pourrait en fait servir un but, contrairement aux autres exemples.
int& foo();
Déclare une fonction nommée foo qui renvoie une référence à un int
. Ce que ces exemples ne parviennent pas à faire est de vous donner une définition de cette fonction que vous pouvez compiler. Si on utilise
int & foo()
{
static int bar = 0;
return bar;
}
Nous avons maintenant une fonction qui renvoie une référence à bar
. puisque bar est static
, il restera actif après l'appel de la fonction, il est donc sûr de renvoyer une référence à cette fonction. Maintenant si nous faisons
foo() = 42;
Ce qui se passe, c’est que nous assignons 42 à bar
puisque nous assignons à la référence et que la référence n’est qu’un alias pour bar
. Si nous appelons à nouveau la fonction comme
std::cout << foo();
Cela afficherait 42 puisque nous avons défini bar
sur ce qui précède.
int &foo();
déclare une fonction appelée foo()
avec le type de retour int&
. Si vous appelez cette fonction sans fournir de corps, vous obtiendrez probablement une erreur de référence non définie.
Lors de votre deuxième tentative, vous avez fourni une fonction int foo()
. Cela a un type de retour différent de la fonction déclarée par int& foo();
. Donc, vous avez deux déclarations du même foo
qui ne correspondent pas, ce qui constitue une violation de la règle de définition unique causant un comportement indéfini (aucun diagnostic requis).
Pour quelque chose qui fonctionne, extrayez la déclaration de la fonction locale. Ils peuvent conduire à un comportement silencieux et non défini, comme vous l'avez vu. Au lieu de cela, utilisez uniquement des déclarations de fonction en dehors de toute fonction. Votre programme pourrait ressembler à:
int &foo()
{
static int i = 2;
return i;
}
int main()
{
++foo();
std::cout << foo() << '\n';
}
int& foo();
est une fonction renvoyant une référence à int
. Votre fonction fournie retourne int
sans référence.
Vous pouvez faire
int& foo()
{
static int i = 42;
return i;
}
int main()
{
int& foo();
foo() = 42;
}
int & foo();
signifie que foo()
renvoie une référence à une variable.
Considérons ce code:
#include <iostream>
int k = 0;
int &foo()
{
return k;
}
int main(int argc,char **argv)
{
k = 4;
foo() = 5;
std::cout << "k=" << k << "\n";
return 0;
}
Ce code imprime:
$ ./a.out k = 5
Parce que foo()
renvoie une référence à la variable globale k
.
Dans votre code révisé, vous convertissez la valeur renvoyée en une référence, qui n'est alors pas valide.
Dans ce contexte, le & signifie une référence - so foo renvoie une référence à un int, plutôt qu'à un int.
Je ne sais pas si vous avez déjà travaillé avec des pointeurs, mais c'est une idée similaire: vous ne restituez pas la valeur de la fonction. Vous transmettez plutôt les informations nécessaires pour trouver l'emplacement en mémoire. int est.
Donc, pour résumer, vous n'attribuez pas de valeur à un appel de fonction - vous utilisez une fonction pour obtenir une référence, puis vous affectez la valeur référencée à une nouvelle valeur. Il est facile de penser que tout se passe en même temps, mais en réalité, l'ordinateur fait tout dans un ordre précis.
Si vous vous demandez - la raison pour laquelle vous obtenez une erreur de segmentation est parce que vous retournez un littéral numérique '2' - c'est donc l'erreur exacte que vous obtiendriez si vous deviez définir un int entier puis essayer de le modifier. valeur.
Si vous ne connaissez pas encore les pointeurs et la mémoire dynamique, je vous le recommande tout d'abord, car il existe quelques concepts difficiles à comprendre, à moins que vous ne les appreniez tous en même temps.
L'exemple de code sur la page liée est juste une déclaration de fonction factice. Cela ne compile pas, mais si vous aviez une fonction définie, cela fonctionnerait en général. L'exemple voulait dire "Si vous aviez une fonction avec cette signature, vous pourriez l'utiliser comme ça".
Dans votre exemple, foo
renvoie clairement une valeur lvalue en fonction de la signature, mais vous retournez une valeur rvalue convertie en valeur lvalue. Ceci est clairement déterminé à échouer. Vous pourriez faire:
int& foo()
{
static int x;
return x;
}
et réussirait en changeant la valeur de x, en disant:
foo() = 10;
La fonction que vous avez, foo (), est une fonction qui renvoie une référence à un entier.
Supposons donc que initialement foo ait renvoyé 5 et que, plus tard, dans votre fonction principale, vous dites foo() = 10;
, puis affiche foo, il en affichera 10 au lieu de 5.
J'espère que cela à du sens :)
Je suis nouveau dans la programmation aussi. C'est intéressant de voir des questions comme celle-ci qui vous font réfléchir! :)