Est-ce que le contenu d'une chaîne est convertible en un autre type?

J'ai reçu l'autre jour d'un de mes anciens (et sympathiques) étudiants au Diplôme de développement du jeu vidéo, un dénommé Jonathan Klang, la question suivante (que je résume pour aller rapidement à l'essentiel): comment peut-on savoir rapidement si le contenu d'une chaîne est convertible en un autre type?

Pour bien suivre l'exemple en réponse à la question posée par Jonathan, il serait préférable d'avoir lu au préalable l'article De texte à autre chose, et inversement ou encore l'article Écrire vos propres conversions explicites de types.

L'exemple de Jonathan était qu'il aimerait écrire une fonction qui vérifierait si une chaîne quelconque était convertible en un entier, de manière à ce que "343432" soit considéré valide mais pas "23423r4".

En fait, la réponse est assez simple : il suffit d'essayer de faire la conversion et de regarder si cela a fonctionné, tout simplement.

Une meilleure réponse encore est d'utiliser le trait std::is_convertible rendu disponible dans <type_traits> depuis C++ 11, mais l'article que vous examinez a été écrit il y a longtemps alors...

Voici du code faisant tout à fait le travail, et pas seulement pour un entier mais bien pour tout type T (dans la mesure où le type est sérialisable). Les (brèves) explications suivent.

#include <sstream>
#include <string>
#include <iostream>

template <class T>
   bool est_convertible_en(const std::string &s)
   {
      std::stringstream sstr;
      sstr << s;
      T val;
      bool convertible = (sstr >> val) != 0;
      // s'il reste quelque chose de non blanc dans s, alors s n'est
      // pas vraiment convertible en T
      char c;
      return convertible && !(sstr >> c);
   }

int main()
{
   using namespace std;
   string s;
   cout << "Entrez la chaîne à convertir (ou ^Z pour terminer) puis <enter>:";
   while (cin >> s)
   {
      if (est_convertible_en<int>(s))
         cout << "La chaîne \"" << s << "\" est convertible en int" << endl;
      else
         cout << "La chaîne \"" << s << "\" n'est pas convertible en int" << endl;
      if (est_convertible_en<float>(s))
         cout << "La chaîne \"" << s << "\" est convertible en float" << endl;
      else
         cout << "La chaîne \"" << s << "\" n'est pas convertible en float" << endl;
      cout << "Entrez la chaîne à convertir (ou ^Z pour terminer) puis <enter> :";
  }
}

Voilà. Sachant que toute donnée sérialisable peut être écrite sur un flux et (si le code de sérialisation et de désérialsiation pour son type est bien écrit) extraite d'un flux de manière symétrique, le code de est_convertible_en<T>(const std::string&) fait simplement la tâche suivante :

Voilà.


Valid XHTML 1.0 Transitional

CSS Valide !