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à!