// { dg-do run { target c++11 } } // { dg-additional-options "-fexcess-precision=fast" } // { dg-skip-if "requires hosted libstdc++ for string" { ! hostedlib } } // An implementation of TR1's <tuple> using variadic teplates // Contributed by Douglas Gregor <doug.gregor@gmail.com> #include <string> #include <cassert> #include <cstring> // Trivial reference_wrapper template<typename T> struct reference_wrapper { reference_wrapper(T& x) : ptr(&x) { } operator T&() const { return *ptr; } T* ptr; }; template<typename T> reference_wrapper<T> ref(T& x) { return x; } template<typename T> reference_wrapper<const T> cref(const T& x) { return x; } // Simple type-traits we'll need template<typename T> struct add_reference { typedef T& type; }; template<typename T> struct add_reference<T&> { typedef T& type; }; template<typename T, typename U> struct is_same { static const bool value = false; }; template<typename T> struct is_same<T, T> { static const bool value = true; }; // For creating the constructor parameters of tuple<> template<typename T> struct add_const_reference { typedef const T& type; }; template<typename T> struct add_const_reference<T&> { typedef T& type; }; // 6.1.3 Class template tuple template<typename... Values> class tuple; template<> class tuple<> { }; template<typename Head, typename... Tail> class tuple<Head, Tail...> : private tuple<Tail...> { typedef tuple<Tail...> inherited; public: tuple() { } // implicit copy-constructor is okay tuple(typename add_const_reference<Head>::type v, typename add_const_reference<Tail>::type... vtail) : m_head(v), inherited(vtail...) { } template<typename... VValues> tuple(const tuple<VValues...>& other) : m_head(other.head()), inherited(other.tail()) { } template<typename... VValues> tuple& operator=(const tuple<VValues...>& other) { m_head = other.head(); tail() = other.tail(); return *this; } typename add_reference<Head>::type head() { return m_head; } typename add_reference<const Head>::type head() const { return m_head; } inherited& tail() { return *this; } const inherited& tail() const { return *this; } protected: Head m_head; }; template<typename T> struct make_tuple_result { typedef T type; }; template<typename T> struct make_tuple_result<reference_wrapper<T> > { typedef T& type; }; // 6.1.3.2 Tuple creation functions struct ignore_t { template<typename T> ignore_t& operator=(const T&) { return *this; } } ignore; template<typename... Values> tuple<typename make_tuple_result<Values>::type...> make_tuple(const Values&... values) { return tuple<typename make_tuple_result<Values>::type...>(values...); } template<typename... Values> tuple<Values&...> tie(Values&... values) { return tuple<Values&...>(values...); } // 6.1.3.3 Tuple helper classes template<typename Tuple> struct tuple_size; template<> struct tuple_size<tuple<> > { static const std::size_t value = 0; }; template<typename Head, typename... Tail> struct tuple_size<tuple<Head, Tail...> > { static const std::size_t value = 1 + tuple_size<tuple<Tail...> >::value; }; template<int I, typename Tuple> struct tuple_element; template<int I, typename Head, typename... Tail> struct tuple_element<I, tuple<Head, Tail...> > { typedef typename tuple_element<I-1, tuple<Tail...> >::type type; }; template<typename Head, typename... Tail> struct tuple_element<0, tuple<Head, Tail...> > { typedef Head type; }; // 6.1.3.4 Element access template<int I, typename Tuple> class get_impl; template<int I, typename Head, typename... Values> class get_impl<I, tuple<Head, Values...> > { typedef typename tuple_element<I-1, tuple<Values...> >::type Element; typedef typename add_reference<Element>::type RJ; typedef typename add_const_reference<Element>::type PJ; typedef get_impl<I-1, tuple<Values...> > Next; public: static RJ get(tuple<Head, Values...>& t) { return Next::get(t.tail()); } static PJ get(const tuple<Head, Values...>& t) { return Next::get(t.tail()); } }; template<typename Head, typename... Values> class get_impl<0, tuple<Head, Values...> > { typedef typename add_reference<Head>::type RJ; typedef typename add_const_reference<Head>::type PJ; public: static RJ get(tuple<Head, Values...>& t) { return t.head(); } static PJ get(const tuple<Head, Values...>& t) { return t.head(); } }; template<int I, typename... Values> typename add_reference< typename tuple_element<I, tuple<Values...> >::type >::type get(tuple<Values...>& t) { return get_impl<I, tuple<Values...> >::get(t); } template<int I, typename... Values> typename add_const_reference< typename tuple_element<I, tuple<Values...> >::type >::type get(const tuple<Values...>& t) { return get_impl<I, tuple<Values...> >::get(t); } // 6.1.3.5 Relational operators inline bool operator==(const tuple<>&, const tuple<>&) { return true; } template<typename T, typename... TTail, typename U, typename... UTail> bool operator==(const tuple<T, TTail...>& t, const tuple<U, UTail...>& u) { return t.head() == u.head() && t.tail() == u.tail(); } template<typename... TValues, typename... UValues> bool operator!=(const tuple<TValues...>& t, const tuple<UValues...>& u) { return !(t == u); } inline bool operator<(const tuple<>&, const tuple<>&) { return false; } template<typename T, typename... TTail, typename U, typename... UTail> bool operator<(const tuple<T, TTail...>& t, const tuple<U, UTail...>& u) { return (t.head() < u.head() || (!(t.head() < u.head()) && t.tail() < u.tail())); } template<typename... TValues, typename... UValues> bool operator>(const tuple<TValues...>& t, const tuple<UValues...>& u) { return u < t; } template<typename... TValues, typename... UValues> bool operator<=(const tuple<TValues...>& t, const tuple<UValues...>& u) { return !(u < t); } template<typename... TValues, typename... UValues> bool operator>=(const tuple<TValues...>& t, const tuple<UValues...>& u) { return !(t < u); } int a0[tuple_size<tuple<> >::value == 0? 1 : -1]; int a1[tuple_size<tuple<int, float, double> >::value == 3? 1 : -1]; int a2a[is_same<tuple_element<0, tuple<int, float, double> >::type, int> ::value? 1 : -1]; int a2b[is_same<tuple_element<1, tuple<int, float, double> >::type, float> ::value? 1 : -1]; int a2c[is_same<tuple_element<2, tuple<int, float, double> >::type, double> ::value? 1 : -1]; int main() { tuple<> t0; tuple<int> t1(1); tuple<int, float> t2(1, 3.14159f); tuple<int, float, const char*> t3a(1, 3.14159f, "Hello, world!"); tuple<long, double, std::string> t3b(t3a); t3b = t3a; // t3a = t3b; DPG: triggers an error, as it should. tuple<int, float, std::string> t3c = ::make_tuple(17, 2.718281828, std::string("Fun")); int seventeen = 17; double pi = 3.14159; tuple<int&, double&> seventeen_pi = make_tuple(ref(seventeen), ref(pi)); tuple<int&, const double&> seventeen_pi2 = make_tuple(ref(seventeen), cref(pi)); tuple<int&, double&> seventeen_pi_tied = tie(seventeen, pi); assert(get<0>(t3a) == 1); assert(get<1>(t3a) == 3.14159f); assert(std::strcmp(get<2>(t3a), "Hello, world!") == 0); assert(t3a == t3b); assert(!(t3a != t3b)); assert(!(t3a < t3b)); assert(!(t3a > t3b)); assert(t3a <= t3b && t3b <= t3a); assert(t3a >= t3b && t3b >= t3a); }