2016-10-06 3 views
0

Pourquoi le .fail() ne fonctionne-t-il pas si je mets un double ou un entier avec caractère comme entrée pour le dernier e accessible?comment arrêter la variable entière de prendre double entrée (chiffres avant décimal) et d'autres valeurs?

J'ai ajouté quelques images de sortie pour ce problème.

Output sample

code:

int main() { 
    string a,b,line; 
    double c; 
    int d,e; 
    stringstream ss; 
    getline(cin,line); 
    ss<<line; 
    ss>>a>>b>>c>>d>>e; 
    cout<<"command: "<<a<<endl<<"arg1: "<<b<<endl<<"arg2: "<<c<<endl<<"arg3: "<<d<<endl<<"arg4: "<<e<<endl; 
    if(ss.fail()) 
     cout<<"Error: invalid command"<<endl; 
    else 
     cout<<"perfect"<<endl; 
    return 0; 
} 

Comment puis-je résoudre ce problème?

Répondre

1

>> cesse de lire dès qu'il trouve une entrée qui ne peut pas être analysée dans le type de données dans lequel il a été dit de lire. Entrée de 7,5 lire dans un int est un 7 parfaitement acceptable et le .5, qui ne peut pas faire partie d'un int, est laissé dans le flux pour déranger la prochaine lecture du flux. Si OP avait l'entrée 7.5 pour le troisième argument (int d), la lecture de .5 dans le quatrième argument (int e) aurait échoué.

Ah. Totalement négligée la partie Comment réparer.

Ma préférence personnelle est de lire toutes les données sous forme de chaîne et d'analyser moi-même. Dans ce cas, j'utiliserais good ol' strtol, principalement parce que je n'ai pas été chaud à l'idée de lancer des exceptions sur une mauvaise entrée de l'utilisateur. Typos arriver. Ils arrivent trop souvent pour être exceptionnels. Faites avec.

Nous lisions dans std::string e, pas int e puis ...

char * endp; // strtol will point endp to character that ended the parsing. 
      // If that's not the end of the string there was stuff we couldn't parse 
errno = 0; // clear the error code so we can catch an overflow error 
      // if the number parsed was too big 
long num = std::strtol(e.c_str(), &endp, 10); // parse the string as a decimal number 
if (*endp != '\0' || errno == ERANGE) 
{ 
    // handle error. Abort, nag user and repeat, whatever 
} 
// use num 

OP a ajouté qu'ils ne sont pas autorisés à utiliser des appels de bibliothèque C. Ainsi soit-il. Le C++ library equivalent is std::stoi. Mon commentaire sur les exceptions ci-dessus explique pourquoi je n'aime pas cette option, mais c'est parti!

size_t end; 
int num = std::stoi(e, &end); // parse the string as a decimal number 
if (end != e.length()) 
{ 
    // handle error. Abort, nag user and repeat, whatever 
} 
// use num 

Si elle ne parvient pas tout à fait de convertir, std::stoi jetteront std::invalid_argument. Si le nombre fourni était trop grand, il lance std::out_of_range, donc attrapez et gérez les exceptions ou laissez le programme s'interrompre. Ton appel.

+0

Merci beaucoup pour votre réponse. Mais je ne suis pas autorisé à utiliser les conversions chaîne-à-entiers de la bibliothèque C (atoi, strtol, etc.) et tout autre chose que la chaîne de type de bibliothèque C++. @ user4581301 –

+0

Dommage. Éditera avec l'équivalent 'std :: stoi'. De retour dans quelques-uns. – user4581301

0
template< typename From,typename To> 
static inline bool superConvert(const From& fromVar,To& toVar) 
{ 
    stringstream ss; 
    ss<<fromVar; 
    ss>>toVar; 
    if(ss.fail()) 
    { 
     return false; 
    } 
    else 
    { 
     From tempFrom; 
     stringstream ss; 
     ss<<toVar; 
     ss>>tempFrom; 
     if(tempFrom != fromVar) 
     { 
      return false; 
     } 
     else 
     { 
      return true; 
     } 
    } 
} 

Pour les entiers, cette fonction fonctionne correctement. Comme il s'agit d'une double vérification, la bonne façon est d'utiliser stdol mais si cela n'est pas autorisé, vous pouvez l'utiliser.

int i; 
bool convertSuccess = superConvert<string,int>("25",i); 
cerr<<i; 
+0

Astuce soignée. Vous aurez quelques problèmes avec le flottant sur ce point, et je recommande de fixer le type 'From' à' std :: string' car une utilisation courante serait superConvert ("25", somenumber); et que "25" va spécialiser le template pour les tableaux 'char' et' if (tempFrom! = fromVar) 'sera toujours vrai. – user4581301

+0

@ user4581301 Merci beaucoup de l'avoir signalé. Tout d'abord, j'ai créé la fonction de conversion de n'importe quel type comme time_t, int ou any à tout. Peut être dans votre cas 'superConvert ("25", somenumber);' marchera. –