Un type uplet maison

Explications à venir (le temps me manque)... Pour plus d'informations, voir ../Sujets/TrucsScouts/Comprendre-tuple.html

#include <algorithm>
using namespace std;

template <class ...>
   class uplet;

template <>
   class uplet<>
   {
   };

template <class T, class ... R>
   class uplet<T, R...> : public uplet<R...>
   {
   public:
      using base_type = uplet<R...>;
      T valeur;
      uplet()
         : base_type{}, valeur{}
      {
      }
      template <class TT, class ... RR>
         uplet(TT&& valeur, RR&&... reste)
            : base_type{forward<RR>(reste)...}, valeur{forward<TT>(valeur)}
         {

         }
   };

//
//
//
template<class ...>
   struct uplet_size;
template<class T, class ... R>
   struct uplet_size<uplet<T, R...>>
   {
      enum { value = 1 + uplet_size<uplet<R...>>::value };
   };
template<>
   struct uplet_size<uplet<>>
   {
      enum { value = 0 };
   };
//
// Mieux (merci à Cedric Van Regemorter et Alexandre Khalifa)
//
//template<class ...>
//   struct uplet_size;
//template<class ... T>
//   struct uplet_size<uplet<T...>>
//   {
//      enum { value = sizeof...(T) };
//   };


//
//
//
template <class ... Args>
   uplet<Args...> make_uplet(Args &&... args)
   {
      return uplet<Args...>{forward<Args>(args)...};
   }

//
//
//
template <int, class ...>
   struct uplet_type_at;
template <int N, class T, class ... R>
   struct uplet_type_at<N, uplet<T, R...>>
   {
      using type = typename uplet_type_at<N-1, uplet<R...>>::type;
   };
template <class T, class ... R>
   struct uplet_type_at<0, uplet<T, R...>>
   {
      using type = T;
   };

//
//
//
template <int, class ...>
   struct search_uplet;
template <int N, class ... T>
   struct search_uplet<N, uplet<T...>>
   {
      using type = typename
         search_uplet<N-1, typename uplet<T...>::base_type>::type;
   };
template <class ... T>
   struct search_uplet<0, uplet<T...>>
   {
      using type = uplet<T...>;
   };

//
//
//
template <int N, class ... T>
   typename uplet_type_at<N, uplet<T...>>::type
      uplet_get(uplet<T...> & zeUplet)
   {
      return static_cast<search_uplet<N, uplet<T...>>::type&>(zeUplet).valeur;
   }
template <int N, class ... T>
   typename uplet_type_at<N, uplet<T...>>::type
      uplet_get(const uplet<T...> & zeUplet)
   {
      return static_cast<const search_uplet<N, uplet<T...>>::type&>(zeUplet).valeur;
   }

//
//
//
template <class ... T>
   bool operator==(const uplet<T...> &a, const uplet<T...> &b)
   {
      using base_type = typename uplet<T...>::base_type;
      return uplet_get<0>(a) == uplet_get<0>(b) &&
             static_cast<const base_type &>(a) == static_cast<const base_type &>(b);
   }
bool operator==(const uplet<> &a, const uplet<> &b)
{
   return true;
}
template <class ... T>
   bool operator!=(const uplet<T...> &a, const uplet<T...> &b)
   {
      return !(a == b);
   }
template <class ... T>
   bool operator<(const uplet<T...> &a, const uplet<T...> &b)
   {
      using base_type = typename uplet<T...>::base_type;
      return uplet_get<0>(a) < uplet_get<0>(b) ||
             uplet_get<0>(a) == uplet_get<0>(b) && static_cast<const base_type &>(a) < static_cast<const base_type &>(b);
   }
bool operator<(const uplet<> &a, const uplet<> &b)
{
   return false;
}

//
//
//
class ignorer {};

template <class T, class ... R>
   void uplet_tie(const uplet<T, R...> &zeUplet, T & val, R & ... reste)
   {
      using base_type = typename uplet<T, R...>::base_type;
      val = uplet_get<0>(zeUplet);
      uplet_tie(static_cast<const base_type&>(zeUplet), reste...);
   }
template <class T, class ... R>
   void uplet_tie(const uplet<T, R...> &zeUplet, ignorer, R & ... reste)
   {
      using base_type = typename uplet<T, R...>::base_type;
      uplet_tie(static_cast<const base_type&>(zeUplet), reste...);
   }
template <class T>
   void uplet_tie(const uplet<T> &zeUplet, T & val)
   {
      val = uplet_get<0>(zeUplet);
   }
template <class T>
   void uplet_tie(const uplet<T> &, ignorer)
   {
   }


class X{};

#include <cassert>
#include <iostream>
using namespace std;

int main()
{
   uplet<int> un;
   uplet<int, float, int, char*> zeUplet;
   auto autUplet = make_uplet(nullptr, 3, 3.14159, "J'aime mon prof", X{});
   cout << uplet_size<uplet<>>::value << ' '
        << uplet_size<uplet<int>>::value << ' '
        << uplet_size<uplet<int, float, int, char*>>::value << ' '
        << uplet_size<decltype(autUplet)>::value << endl;
   cout << "Taille du type a la position 3 dans autUplet: "
        << sizeof(uplet_type_at<3, decltype(autUplet)>::type)
        << " bytes" << endl;
   cout << "Valeur a la position 1 dans autUplet: "
        << uplet_get<3>(autUplet) << endl;

   auto ua = make_uplet(1, 2.0, 3), ub = make_uplet(1, 2.0, 3), uc = make_uplet(1,2.5,3);
   assert(ua == ub);
   assert(ua != uc);
   assert(!(ua < ub));
   assert(ua < uc);
   {
      int val0, val2;
      double val1;
      uplet_tie(uc, val0, val1, val2);
      cout << "Valeurs de uc: " << val0 << ' ' << val1 << ' ' << val2 << endl;
   }
   {
      int val2;
      double val1;
      uplet_tie(uc, ignorer{}, val1, val2);
      cout << "Valeurs de uc, en ignorant la premiere: " << val1 << ' ' << val2 << endl;
   }
}

Voilà!


Valid XHTML 1.0 Transitional

CSS Valide !