web-dev-qa-db-fra.com

Que signifie "int & foo ()" en C ++?

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?

111
Sossisos

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
}
164
TartanLlama

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.

70
Kate Gregory
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.

31
NathanOliver

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';
}
15
M.M

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;
}
10
Jarod42

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.

7
vy32

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.

5
Dar Brett

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;
4
IceFire

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! :)

3
psj01