// tuple_basic.hpp ----------------------------------------------------- // Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi) // // Permission to copy, use, sell and distribute this software is granted // provided this copyright notice appears in all copies. // Permission to modify the code and to distribute modified code is granted // provided this copyright notice appears in all copies, and a notice // that the code was modified is included with the copyright notice. // // This software is provided "as is" without express or implied warranty, // and with no claim as to its suitability for any purpose. // For more information, see http://www.boost.org // Outside help: // This and that, Gary Powell. // Fixed return types for get_head/get_tail // ( and other bugs ) per suggestion of Jens Maurer // simplified element type accessors + bug fix (Jeremy Siek) // Several changes/additions according to suggestions by Doug Gregor, // William Kempf, Vesa Karvonen, John Max Skaller, Ed Brey, Beman Davis, // David Abrahams. // Revision history: // 2001 08 30 David Abrahams // Added default constructor for cons<>. // ----------------------------------------------------------------- #ifndef BOOST_TUPLE_BASIC_HPP #define BOOST_TUPLE_BASIC_HPP #include // needed for the assignment from pair to tuple #include "boost/type_traits/cv_traits.hpp" namespace boost { namespace tuples { // -- null_type -------------------------------------------------------- struct null_type {}; // a helper function to provide a const null_type type temporary namespace detail { inline const null_type cnull_type() { return null_type(); } } // end detail // - cons forward declaration ----------------------------------------------- template struct cons; // - tuple forward declaration ----------------------------------------------- template < class T0 = null_type, class T1 = null_type, class T2 = null_type, class T3 = null_type, class T4 = null_type, class T5 = null_type, class T6 = null_type, class T7 = null_type, class T8 = null_type, class T9 = null_type> class tuple; // tuple_length forward declaration template struct length; namespace detail { // -- generate error template, referencing to non-existing members of this // template is used to produce compilation errors intentionally template class generate_error; // tuple default argument wrappers --------------------------------------- // Work for non-reference types, intentionally not for references template struct default_arg { // Non-class temporaries cannot have qualifiers. // To prevent f to return for example const int, we remove cv-qualifiers // from all temporaries. static typename boost::remove_cv::type f() { return T(); } }; // This is just to produce a more informative error message // The code would fail in any case template struct default_arg { static T* f() { return generate_error::arrays_are_not_valid_tuple_elements; } }; template struct default_arg { static T& f() { #ifndef __sgi return generate_error::no_default_values_for_reference_types; #else // MIPSpro instantiates functions even when it should not, so // this technique can not be used for error checking. // The simple workaround is to just not have this error checking // with MIPSpro. static T x; return x; #endif } }; // - cons getters -------------------------------------------------------- // called: get_class::get(aTuple) template< int N > struct get_class { template inline static RET get(const cons& t) { return get_class::template get(t.tail); } template inline static RET get(cons& t) { return get_class::template get(t.tail); } }; template<> struct get_class<0> { template inline static RET get(const cons& t) { return t.head; } template inline static RET get(cons& t) { return t.head; } }; } // end of namespace detail // -cons type accessors ---------------------------------------- // typename tuples::element::type gets the type of the // Nth element ot T, first element is at index 0 // ------------------------------------------------------- template struct element { private: typedef typename T::tail_type Next; public: typedef typename element::type type; }; template struct element<0,T> { typedef typename T::head_type type; }; // -get function templates ----------------------------------------------- // Usage: get(aTuple) // -- some traits classes for get functions // access traits lifted from detail namespace to be part of the interface, // (Joel de Guzman's suggestion). Rationale: get functions are part of the // interface, so should the way to express their return types be. template struct access_traits { typedef const T& const_type; typedef T& non_const_type; typedef const typename boost::remove_cv::type& parameter_type; // used as the tuple constructors parameter types // Rationale: non-reference tuple element types can be cv-qualified. // It should be possible to initialize such types with temporaries, // and when binding temporaries to references, the reference must // be non-volatile and const. 8.5.3. (5) }; template struct access_traits { typedef T& const_type; typedef T& non_const_type; typedef T& parameter_type; }; // get function for non-const cons-lists, returns a reference to the element template inline typename access_traits< typename element >::type >::non_const_type get(cons& c) { return detail::get_class::template get< typename access_traits< typename element >::type >::non_const_type>(c); } // get function for const cons-lists, returns a const reference to // the element. If the element is a reference, returns the reference // as such (that is, can return a non-const reference) template inline typename access_traits< typename element >::type >::const_type get(const cons& c) { return detail::get_class::template get< typename access_traits< typename element >::type >::const_type>(c); } // -- the cons template -------------------------------------------------- template struct cons { typedef HT head_type; typedef TT tail_type; head_type head; tail_type tail; typename access_traits::non_const_type get_head() { return head; } typename access_traits::non_const_type get_tail() { return tail; } typename access_traits::const_type get_head() const { return head; } typename access_traits::const_type get_tail() const { return tail; } cons() : head(detail::default_arg::f()), tail() {} // the argument for head is not strictly needed, but it prevents // array type elements. This is good, since array type elements // cannot be supported properly in any case (no assignment, // copy works only if the tails are exactly the same type, ...) cons(typename access_traits::parameter_type h, const tail_type& t) : head (h), tail(t) {} template cons( T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, T10& t10 ) : head (t1), tail (t2, t3, t4, t5, t6, t7, t8, t9, t10, detail::cnull_type()) {} template cons( const cons& u ) : head(u.head), tail(u.tail) {} template cons& operator=( const cons& u ) { head=u.head; tail=u.tail; return *this; } // must define assignment operator explicitly, implicit version is // illformed if HT is a reference (12.8. (12)) cons& operator=(const cons& u) { head = u.head; tail = u.tail; return *this; } template cons& operator=( const std::pair& u ) { BOOST_STATIC_ASSERT(length::value == 2); // check length = 2 head = u.first; tail.head = u.second; return *this; } // get member functions (non-const and const) template typename access_traits< typename element >::type >::non_const_type get() { return boost::get(*this); // delegate to non-member get } template typename access_traits< typename element >::type >::const_type get() const { return boost::get(*this); // delegate to non-member get } }; template struct cons { typedef HT head_type; typedef null_type tail_type; head_type head; typename access_traits::non_const_type get_head() { return head; } null_type get_tail() { return null_type(); } typename access_traits::const_type get_head() const { return head; } const null_type get_tail() const { return null_type(); } cons() : head(detail::default_arg::f()) {} cons(typename access_traits::parameter_type h, const null_type& = null_type()) : head (h) {} template cons(T1& t1, const null_type&, const null_type&, const null_type&, const null_type&, const null_type&, const null_type&, const null_type&, const null_type&, const null_type&) : head (t1) {} template cons( const cons& u ) : head(u.head) {} template cons& operator=(const cons& u ) { head = u.head; return *this; } // must define assignment operator explicitely, implicit version // is illformed if HT is a reference cons& operator=(const cons& u) { head = u.head; return *this; } template typename access_traits< typename element::type >::non_const_type get() { return boost::get(*this); } template typename access_traits< typename element::type >::const_type get() const { return boost::get(*this); } }; // templates for finding out the length of the tuple ------------------- template struct length { BOOST_STATIC_CONSTANT(int, value = 1 + length::value); }; template<> struct length { BOOST_STATIC_CONSTANT(int, value = 0); }; namespace detail { // Tuple to cons mapper -------------------------------------------------- template struct map_tuple_to_cons { typedef cons::type > type; }; // The empty tuple is a null_type template <> struct map_tuple_to_cons { typedef null_type type; }; } // end detail // ------------------------------------------------------------------- // -- tuple ------------------------------------------------------ template class tuple : public detail::map_tuple_to_cons::type { public: typedef typename detail::map_tuple_to_cons::type inherited; typedef typename inherited::head_type head_type; typedef typename inherited::tail_type tail_type; // access_traits::parameter_type takes non-reference types as const T& explicit tuple( typename access_traits::parameter_type t0 = detail::default_arg::f(), typename access_traits::parameter_type t1 = detail::default_arg::f(), typename access_traits::parameter_type t2 = detail::default_arg::f(), typename access_traits::parameter_type t3 = detail::default_arg::f(), typename access_traits::parameter_type t4 = detail::default_arg::f(), typename access_traits::parameter_type t5 = detail::default_arg::f(), typename access_traits::parameter_type t6 = detail::default_arg::f(), typename access_traits::parameter_type t7 = detail::default_arg::f(), typename access_traits::parameter_type t8 = detail::default_arg::f(), typename access_traits::parameter_type t9 = detail::default_arg::f()) : inherited(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) {} template tuple(const cons& p) : inherited(p) {} template tuple& operator=(const cons& k) { inherited::operator=(k); return *this; } template tuple& operator=(const std::pair& k) { BOOST_STATIC_ASSERT(length::value == 2);// check_length = 2 this->head = k.first; this->tail.head = k.second; return *this; } }; // The empty tuple template <> class tuple : public null_type { public: typedef null_type inherited; }; // Swallows any assignment (by Doug Gregor) namespace detail { struct swallow_assign { template swallow_assign& operator=(const T&) { return *this; } }; } // namespace detail // "ignore" allows tuple positions to be ignored when using "tie". namespace { detail::swallow_assign ignore; } // --------------------------------------------------------------------------- // The call_traits for make_tuple // Honours the reference_wrapper class. // Must be instantiated with plain or const plain types (not with references) // from template foo(const T& t) : make_tuple_traits::type // from template foo(T& t) : make_tuple_traits::type // Conversions: // T -> T, // references -> compile_time_error // reference_wrapper -> T& // const reference_wrapper -> T& // array -> const ref array template struct make_tuple_traits { typedef T type; // commented away, see below (JJ) // typedef typename IF< // boost::is_function::value, // T&, // T>::RET type; }; // The is_function test was there originally for plain function types, // which can't be stored as such (we must either store them as references or // pointers). Such a type could be formed if make_tuple was called with a // reference to a function. // But this would mean that a const qualified function type was formed in // the make_tuple function and hence make_tuple can't take a function // reference as a parameter, and thus T can't be a function type. // So is_function test was removed. // (14.8.3. says that type deduction fails if a cv-qualified function type // is created. (It only applies for the case of explicitly specifying template // args, though?)) (JJ) template struct make_tuple_traits { typedef typename detail::generate_error:: do_not_use_with_reference_type error; }; // Arrays can't be stored as plain types; convert them to references. // All arrays are converted to const. This is because make_tuple takes its // parameters as const T& and thus the knowledge of the potential // non-constness of actual argument is lost. template struct make_tuple_traits { typedef const T (&type)[n]; }; template struct make_tuple_traits { typedef const T (&type)[n]; }; template struct make_tuple_traits { typedef const volatile T (&type)[n]; }; template struct make_tuple_traits { typedef const volatile T (&type)[n]; }; template struct make_tuple_traits >{ typedef T& type; }; template struct make_tuple_traits >{ typedef T& type; }; namespace detail { // a helper traits to make the make_tuple functions shorter (Vesa Karvonen's // suggestion) template < class T0 = null_type, class T1 = null_type, class T2 = null_type, class T3 = null_type, class T4 = null_type, class T5 = null_type, class T6 = null_type, class T7 = null_type, class T8 = null_type, class T9 = null_type > struct make_tuple_mapper { typedef tuple::type, typename make_tuple_traits::type, typename make_tuple_traits::type, typename make_tuple_traits::type, typename make_tuple_traits::type, typename make_tuple_traits::type, typename make_tuple_traits::type, typename make_tuple_traits::type, typename make_tuple_traits::type, typename make_tuple_traits::type> type; }; } // end detail // -make_tuple function templates ----------------------------------- inline tuple<> make_tuple() { return tuple<>(); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0) { return typename detail::make_tuple_mapper::type(t0); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1) { return typename detail::make_tuple_mapper::type(t0, t1); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1, const T2& t2) { return typename detail::make_tuple_mapper::type(t0, t1, t2); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3) { return typename detail::make_tuple_mapper::type (t0, t1, t2, t3); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4) { return typename detail::make_tuple_mapper::type (t0, t1, t2, t3, t4); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) { return typename detail::make_tuple_mapper::type (t0, t1, t2, t3, t4, t5); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) { return typename detail::make_tuple_mapper ::type (t0, t1, t2, t3, t4, t5, t6); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7) { return typename detail::make_tuple_mapper ::type (t0, t1, t2, t3, t4, t5, t6, t7); } template inline typename detail::make_tuple_mapper ::type make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8) { return typename detail::make_tuple_mapper ::type (t0, t1, t2, t3, t4, t5, t6, t7, t8); } template inline typename detail::make_tuple_mapper ::type make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8, const T9& t9) { return typename detail::make_tuple_mapper ::type (t0, t1, t2, t3, t4, t5, t6, t7, t8, t9); } // Tie function templates ------------------------------------------------- template inline tuple tie(T1& t1) { return tuple (t1); } template inline tuple tie(T1& t1, T2& t2) { return tuple (t1, t2); } template inline tuple tie(T1& t1, T2& t2, T3& t3) { return tuple (t1, t2, t3); } template inline tuple tie(T1& t1, T2& t2, T3& t3, T4& t4) { return tuple (t1, t2, t3, t4); } template inline tuple tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) { return tuple (t1, t2, t3, t4, t5); } template inline tuple tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6) { return tuple (t1, t2, t3, t4, t5, t6); } template inline tuple tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7) { return tuple (t1, t2, t3, t4, t5, t6, t7); } template inline tuple tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8) { return tuple (t1, t2, t3, t4, t5, t6, t7, t8); } template inline tuple tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9) { return tuple (t1, t2, t3, t4, t5, t6, t7, t8, t9); } template inline tuple tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, T10& t10) { return tuple (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); } } // end of namespace tuples } // end of namespace boost #endif // BOOST_TUPLE_BASIC_HPP