C++ - valeur renvoyée par std::cin

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je débute le cours sur la programmation C++. J’apprends que std::cin renvoie une valeur qui peut être traitée par un if (ou autres itérateurs) afin de gérer les erreurs de saisie. Naïvement j’ai créé un booléen "saisie" et j’ai fait le code ci-dessous. Mais ça ne compile pas. Par contre si on supprime la variable "saisie" et qu’on met "std::cin » age" dans les parenthèse du if, ça fonctionne. Ma question est pourquoi?

Ma première réponse est que cin ne renvoie pas un booléen et que if est capable de traiter d’autres types. Quel est le type renvoyé par cin? En allant ici : https://en.cppreference.com/w/cpp/io/cin , je trouve le prototype de cin qui est : "extern std::istream cin;". du coup de déclare "saisie" comme étant de type extern std::istream et dans les parenthèses du if je mets la variable "saisie". Mais ça ne fonctionne. Je ne comprends donc pas ce que renvoie std::cin. Est-ce que quelqu’un peut m’éclairer? D’avance merci.

int main(){

    std::cout << "Donnez votre âge : " << std::endl;
    int age {};
    extern std::istream saisie;
    
    saisie = std::cin >> age;
    
    if(saisie)
       std::cout << age << std::endl;
    else {
       std::cout << "erreur de saisie" << std::endl;
       std::cin.clear();
       std::cin.ignore(255,'\n');
   }
    

    return 0;
}
+0 -0

J’apprends que std::cin renvoie une valeur qui peut être traitée par un if (ou autres itérateurs)

std::cin ne renvoi rien, c’est une variable. Et si elle est externe, se sont pour des raisons liées au variable globale.

Ce qui renvoi quelque chose est la fonction operator>>, qui va retourner le flux. Donc une référence vers std::cin pour std::cin >> age. Par conséquent

if (std::cin >> age) {
  ...
}

est équivalent à

std::cin >> age;
if (std::cin) {
  ...
}

Et si le if compile, c’est grâce à l’opérateur de conversion vers un bool qui est une écriture plus courte pour if (!std::cin.fail()).

(grillé)

std::cin n’est pas une fonction, c’est un objet de type std::istream. Il ne renvoie rien, il représente simplement l’entrée standard du programme. Ce qui renvoie une valeur, c’est l’opérateur >> appelé sur cet objet. Et ce qui est renvoyé, c’est simplement std::cin lui-même. Pourquoi ? Pour pouvoir appeler cet opérateur en chaine. Exemple :

std::cin >> a >> b;

// équivalent à
(std::cin >> a) >> b; // l'expression entre parenthèse renvoie std::cin

// équivalent à
std::cin >> a;
std::cin >> b;

Pour répondre à tes autres questions:

  1. Tu ne peux pas stocker ce que renvoie cet opérateur dans une variable, parce que la construction par copie et l’opérateur = sont interdits (ce sont des deleted functions). En effet, les flux d’entrée ne sont pas des objets copiables entre eux (cf. sémantique d’entité).
  2. La raison pour laquelle tu peux tester l’expression std::cin >> a dans un if est la suivante. Un if ne peut tester que des valeurs numériques (bool compris). Si if reçoit un autre type d’objet, il essaie de le convertir implicitement dans un type adéquat. En l’occurrence, le type std::istream est convertissable en bool. La valeur retournée par cet opérateur est false si une erreur est survenu sur le flux, sinon true.

Naïvement j’ai créé un booléen "saisie" et j’ai fait le code ci-dessous. Mais ça ne compile pas.

forTheGame

Ça compile bien si tu initialise ta variable avec des accolades :

bool success { std::cin >> a };
if (success)
    // ...

Ça fait peut-être beaucoup d’information pour quelqu’un qui débute. N’hésite pas à poser d’autres questions si tu as besoin de précisions.

Petit conseil : quand tu définis une variable dont le type dépend directement du retour d’une fonction (ou d’une expression), utilise le mot clé auto.

Merci pour vos réponses. Oui je me suis emmêlé les pinceaux entre les variables, les objets et les fonctions. De toute évidence je ne sais pas lire la documentation disponible dans cppreference.com. Je dois avouer que je ne la trouve pas accueillante.

Ok,Std::cin n’est pas une fonction et ne peut rien renvoyer. " std::cin " est un objet et " » " est une fonction qui prend un premier argument de type " std::istream " et un second argument de type classique (int, double, string, …) et qui renvoie son premier argument.

On peut dire que " std::cin » a " est une façon courte d’écrire en tirant un peu par les cheveux "std::cin » (std::cin, a) " si je veux l’écrire façon déclaration de fonction, non ?

@Olybri : sur le point 1 tu m’as perdu. Mais je garde ça dans un coin de ma tête je suis sûr que ça va me servir quand j’aurais plus avancé dans le cours.

Vos réponses sont éclairantes. Vous m’avez fait réaliser que les opérateurs sont des fonctions. Je pourrais aussi dire que l’opérateur + est une fonction qui prend 2 arguments et renvoie la somme de ses 2 arguments. C’est bête à dire mais je ne voyais pas les choses comme ça parce que ça n’a pas la forme classique d’une déclaration de fonction. Du coup est-ce qu’on peut dire que « int » est une fonction qui prend un ou plusieurs arguments sans type et qui réserve une quantité de mémoire ? Si le « int » ne peut pas avoir la quantité de mémoire demandée. Est-ce qu’il renvoie une erreur ? J’imagine que mes questions sur le « int » sont un peu tordues, mais ça me laisse songeur.

+0 -0

On peut dire que " std::cin » a " est une façon courte d’écrire en tirant un peu par les cheveux "std::cin » (std::cin, a) " ?

Plutôt operator»(std::cin, a)

Qui est un code tout à fait valide.

@Olybri : sur le point 1 tu m’as perdu. Mais je garde ça dans un coin de ma tête je suis sûr que ça va me servir quand j’aurais plus avancé dans le cours.

Ce sont des restrictions associées au type. Certaine classe empêche la copie et l’expression std::istream mycin = std::cin n’est pas permise, seul une référence pourra être utilisé std::istream& mycin = std::cin.

Du coup est-ce qu’on peut dire que « int » est une fonction qui prend un ou plusieurs arguments sans type et qui réserve une quantité de mémoire ?

On peut l’utiliser « comme » une fonction (foo(int(x))), mais la comparaison s’arrête là. Les fonctions et les types sont 2 choses complètement différente, l’une à une valeur (une fonction à une adresse mémoire) et l’autre est un type. Une valeur à forcement un type (du genre pointeur de fonction pour une fonction) et un type sert à définir les restrictions d’une valeur, ils n’ont plus d’existence dans le programme compilé.

Au passage, la forme int(x) est la même que pour construire n’importe quel objet, on peut faire int{x} ou l’associé à une variable int age {x};. Dans tous les cas, c’est une conversion/construction (ou une copie) de x vers le type int.

Si le « int » ne peut pas avoir la quantité de mémoire demandée. Est-ce qu’il renvoie une erreur ?

Ce n’est pas lui qui renvoi une erreur, mais l’OS suite à un dépassement de la pile d’exécution. Et c’est généralement fatal.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte