Implémentation complète de lexical_cast

Le code de cet exemple vient en deux versions (deux « saveurs »), soit C++ 03 et C++ 11. Avec la version C++ 03, certains traits sont implémentés manuellement, alors qu'ils sont offerts par le standard depuis C++ 11. Bien entendu, préférez C++ 11 si votre compilateur le supporte.

Version C++ 11

Ceci est une implémentation complète (dans la mesure de ce que j'ai choisi de faire; on pourrait aller plus loin et considérer les cas où const char* et const wchar_t* servent de type source pour les conversions texte à texte) de lexical_cast (dont nous avons discuté dans l'article disponible ici).

#include <type_traits>
#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>

class implicite   {};
class texte_dest  {};
class texte_texte {};
class general     {};

template <class>
   struct est_texte : std::false_type {
   };
template <class C>
   struct est_texte<std::basic_string<C>> : std::true_type {
   };
 
template <class D, class S>
   struct traits_conversion {
      using type = std::conditional_t<
         std::is_same<D,S>::value || std::is_convertible<S, D>::value,
         implicite,
         std::conditional_t<
            est_texte<D>::value,
            std::conditional_t<
               est_texte<S>::value,
               texte_texte,
               texte_dest
            >,
            general
         >
      >;
   };
 
template <class D, class S>
   D lexical_cast(const S &src, general) {
      stringstream sstr;
      sstr << src;
      D dest;
      sstr >> dest;
      return dest;
   }
template <class D, class S>
   D lexical_cast(const S &src, texte_dest) {
      using value_type = typename D::value_type;
      basic_stringstream<value_type> sstr;
      sstr << src;
      return sstr.str();
   }
template <class D, class S>
   D lexical_cast(const S &src, texte_texte) {
      return { begin(src), end(src) };
   }
template <class D, class S>
   D lexical_cast(const S &src, implicite) {
      return src;
   }
 
//#include <iostream>
//template <class T, class U>
//   void diag() {
//      using namespace std;
//      cout << typeid(T).name() << " <-- \n\t" << typeid(U).name() << endl;
//      cout << "\tMeme type? " << is_same<T,U>::value << endl;
//      cout << "\t" << typeid(traits_conversion<T, U>::type()).name() << endl;
//   }
 
template <class D, class S>
   D lexical_cast(S &&src) {
      //diag<D, S>();
      return lexical_cast<D, S>(std::forward<S>(src), typename traits_conversion<D, S>::type{});
   }
#include <iostream> 
using namespace std; 

class X {};
istream& operator>>(istream &is, X&) {
   return is;
}
ostream& operator<<(ostream &os, const X&) {
   return os;
}
 
struct Y {
   Y() = default;
   Y(const X&) {}
};
istream& operator>>(istream &is, Y&) {
   return is;
}
ostream& operator<<(ostream &os, const Y&) {
   return os;
}
 
int main() {
   string s = "3";
   auto i = lexical_cast<int>(s); // sérialisation par flux
   s = lexical_cast<string>(i);  // sérialisation par flux, texte en sortie
   auto ws = lexical_cast<wstring>(i);  // idem
   s = lexical_cast<string>(s);  // implicite
   ws = lexical_cast<wstring>(s); // texte à texte
   s = lexical_cast<string>(ws); // idem
   X x;
   Y y;
   y = lexical_cast<Y>(x); // implicite
   x = lexical_cast<X>(y); // via flux
}

Version C++ 03

Pour en savoir plus sur quelques outils auxiliaires utilisés ci-dessous, voir :

Ceci est une implémentation complète (dans la mesure de ce que j'ai choisi de faire; on pourrait aller plus loin et considérer les cas où const char* et const wchar_t* servent de type source pour les conversions texte à texte) de lexical_cast (dont nous avons discuté dans l'article disponible ici).

#include <string>
#include <sstream>
#include <iostream>
using namespace std;

class implicite   {};
class texte_dest  {};
class texte_texte {};
class general     {};

template <bool, class, class>
   struct static_if_else;
template <class SiVrai, class SiFaux>
   struct static_if_else<true, SiVrai, SiFaux> {
      typedef SiVrai type;
   };
template <class SiVrai, class SiFaux>
   struct static_if_else<false, SiVrai, SiFaux> {
      typedef SiFaux type;
   };

template <class T, class U>
   struct meme_type {
      enum { value = false };
   };
template <class T>
   struct meme_type<T,T> {
      enum { value = true };
   };

template <class S, class D>
   class est_convertible {
      typedef char oui_type;
      struct non_type { char _[3]; } ;
      static oui_type test(D);
      static non_type test(...);
      static S creer();
   public:
      enum { value = sizeof(test(creer()))==sizeof(oui_type) };
   };

template <class>
   struct est_texte {
      enum { value = false };
   };
template <class C>
   struct est_texte<basic_string<C> > {
      enum { value = true };
   };

template <class D, class S>
   struct traits_conversion {
      typedef typename static_if_else<
         meme_type<D,S>::value || est_convertible<S, D>::value,
         implicite,
         typename static_if_else<
            est_texte<D>::value,
            typename static_if_else<
               est_texte<S>::value,
               texte_texte,
               texte_dest
            >::type,
            general
         >::type
      >::type type;
   };


template <class D, class S>
   D lexical_cast(const S &src, general) {
      stringstream sstr;
      sstr << src;
      D dest;
      sstr >> dest;
      return dest;
   }
template <class D, class S>
   D lexical_cast(const S &src, texte_dest) {
      typedef typename
         D::value_type value_type;
      basic_stringstream<value_type> sstr;
      sstr << src;
      return sstr.str();
   }
template <class D, class S>
   D lexical_cast(const S &src, texte_texte) {
      return D(src.begin(), src.end());
   }
template <class D, class S>
   D lexical_cast(const S &src, implicite) {
      return src;
   }

//template <class T, class U>
//   void diag() {
//      cout << typeid(T).name() << " <-- \n\t" << typeid(U).name() << endl;
//      cout << "\tMeme type? " << meme_type<T,U>::value << endl;
//      cout << "\t" << typeid(traits_conversion<T, U>::type()).name() << endl;
//   }

template <class D, class S>
   D lexical_cast(const S &src) {
      //diag<D, S>();
      return lexical_cast<D, S>(src, typename traits_conversion<D, S>::type());
   }

class X {};
istream& operator>>(istream &is, X&) {
   return is;
}
ostream& operator<<(ostream &os, const X&) {
   return os;
}

struct Y {
   Y() { }
   Y(const X&) {}
};
istream& operator>>(istream& is, Y&) {
   return is;
}
ostream& operator<<(ostream&os, const Y&) {
   return os;
}

int main() {
   string s = "3";
   int i = lexical_cast<int>(s); // sérialisation par flux
   s = lexical_cast<string>(i);  // sérialisation par flux, texte en sortie
   s = lexical_cast<string>(s);  // implicite
   wstring ws = lexical_cast<wstring>(s); // texte à texte
   X x;
   Y y;
   y = lexical_cast<Y>(x); // implicite
   x = lexical_cast<X>(y); // via flux
}

Valid XHTML 1.0 Transitional

CSS Valide !