// tuple_basic.hpp ----------------------------------------------------- // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // 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 Douglas Gregor, // William Kempf, Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, // David Abrahams. // Revision history: // 2002 05 01 Hugo Duncan: Fix for Borland after Jaakko's previous changes // 2002 04 18 Jaakko: tuple element types can be void or plain function // types, as long as no object is created. // Tuple objects can no hold even noncopyable types // such as arrays. // 2001 10 22 John Maddock // Fixes for Borland C++ // 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" #include "boost/type_traits/function_traits.hpp" #include "boost/detail/workaround.hpp" // needed for BOOST_WORKAROUND 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() { return null_type(); } // -- if construct ------------------------------------------------ // Proposed by Krzysztof Czarnecki and Ulrich Eisenecker template struct IF { typedef Then RET; }; template struct IF { typedef Else RET; }; } // 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; // - cons getters -------------------------------------------------------- // called: get_class::get(aTuple) template< int N > struct get_class { template inline static RET get(const cons& t) { #if BOOST_WORKAROUND(__IBMCPP__,==600) // vacpp 6.0 is not very consistent regarding the member template keyword // Here it generates an error when the template keyword is used. return get_class::get(t.tail); #else return get_class::BOOST_NESTED_TEMPLATE get(t.tail); #endif } template inline static RET get(cons& t) { #if BOOST_WORKAROUND(__IBMCPP__,==600) return get_class::get(t.tail); #else return get_class::BOOST_NESTED_TEMPLATE get(t.tail); #endif } }; 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 // ------------------------------------------------------- #ifndef BOOST_NO_CV_SPECIALIZATIONS 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; }; template struct element { private: typedef typename T::tail_type Next; typedef typename element::type unqualified_type; public: #if BOOST_WORKAROUND(__BORLANDC__,<0x600) typedef const unqualified_type type; #else typedef typename boost::add_const::type type; #endif }; template struct element<0,const T> { #if BOOST_WORKAROUND(__BORLANDC__,<0x600) typedef const typename T::head_type type; #else typedef typename boost::add_const::type type; #endif }; #else // def BOOST_NO_CV_SPECIALIZATIONS namespace detail { template struct element_impl { private: typedef typename T::tail_type Next; public: typedef typename element_impl::type type; }; template struct element_impl { private: typedef typename T::tail_type Next; public: typedef const typename element_impl::type type; }; template struct element_impl<0, T, false /* IsConst */> { typedef typename T::head_type type; }; template struct element_impl<0, T, true /* IsConst */> { typedef const typename T::head_type type; }; } // end of namespace detail template struct element: public detail::element_impl::value> { }; #endif // -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 BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int, N)) { #if BOOST_WORKAROUND(__IBMCPP__,==600 ) return detail::get_class:: #else return detail::get_class::BOOST_NESTED_TEMPLATE #endif get< typename access_traits< typename element >::type >::non_const_type, HT,TT >(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 BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int, N)) { #if BOOST_WORKAROUND(__IBMCPP__,==600) return detail::get_class:: #else return detail::get_class::BOOST_NESTED_TEMPLATE #endif get< typename access_traits< typename element >::type >::const_type, HT,TT >(c); } // -- the cons template -------------------------------------------------- namespace detail { // These helper templates wrap void types and plain function types. // The reationale is to allow one to write tuple types with those types // as elements, even though it is not possible to instantiate such object. // E.g: typedef tuple some_type; // ok // but: some_type x; // fails template class non_storeable_type { non_storeable_type(); }; template struct wrap_non_storeable_type { typedef typename IF< ::boost::is_function::value, non_storeable_type, T >::RET type; }; template <> struct wrap_non_storeable_type { typedef non_storeable_type type; }; } // detail template struct cons { typedef HT head_type; typedef TT tail_type; typedef typename detail::wrap_non_storeable_type::type stored_head_type; stored_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(), 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()) {} template cons( const null_type& /*t1*/, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, T10& t10 ) : head (), tail (t2, t3, t4, t5, t6, t7, t8, t9, t10, detail::cnull()) {} 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::tuples::get(*this); // delegate to non-member get } template typename access_traits< typename element >::type >::const_type get() const { return boost::tuples::get(*this); // delegate to non-member get } }; template struct cons { typedef HT head_type; typedef null_type tail_type; typedef cons self_type; typedef typename detail::wrap_non_storeable_type::type stored_head_type; stored_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() : head() {} 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) {} cons(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&, const null_type&) : head () {} 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(BOOST_EXPLICIT_TEMPLATE_NON_TYPE(int, N)) { return boost::tuples::get(*this); } template typename access_traits< typename element::type >::const_type get(BOOST_EXPLICIT_TEMPLATE_NON_TYPE(int, N)) const { return boost::tuples::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); }; template<> struct length const> { BOOST_STATIC_CONSTANT(int, value = 0); }; template<> struct length { BOOST_STATIC_CONSTANT(int, value = 0); }; 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& tuple() {} tuple(typename access_traits::parameter_type t0) : inherited(t0, detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1) : inherited(t0, t1, detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2) : inherited(t0, t1, t2, detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2, typename access_traits::parameter_type t3) : inherited(t0, t1, t2, t3, detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2, typename access_traits::parameter_type t3, typename access_traits::parameter_type t4) : inherited(t0, t1, t2, t3, t4, detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2, typename access_traits::parameter_type t3, typename access_traits::parameter_type t4, typename access_traits::parameter_type t5) : inherited(t0, t1, t2, t3, t4, t5, detail::cnull(), detail::cnull(), detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2, typename access_traits::parameter_type t3, typename access_traits::parameter_type t4, typename access_traits::parameter_type t5, typename access_traits::parameter_type t6) : inherited(t0, t1, t2, t3, t4, t5, t6, detail::cnull(), detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2, typename access_traits::parameter_type t3, typename access_traits::parameter_type t4, typename access_traits::parameter_type t5, typename access_traits::parameter_type t6, typename access_traits::parameter_type t7) : inherited(t0, t1, t2, t3, t4, t5, t6, t7, detail::cnull(), detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2, typename access_traits::parameter_type t3, typename access_traits::parameter_type t4, typename access_traits::parameter_type t5, typename access_traits::parameter_type t6, typename access_traits::parameter_type t7, typename access_traits::parameter_type t8) : inherited(t0, t1, t2, t3, t4, t5, t6, t7, t8, detail::cnull()) {} tuple(typename access_traits::parameter_type t0, typename access_traits::parameter_type t1, typename access_traits::parameter_type t2, typename access_traits::parameter_type t3, typename access_traits::parameter_type t4, typename access_traits::parameter_type t5, typename access_traits::parameter_type t6, typename access_traits::parameter_type t7, typename access_traits::parameter_type t8, typename access_traits::parameter_type t9) : 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 const& operator=(const T&) const { return *this; } }; } // namespace detail // "ignore" allows tuple positions to be ignored when using "tie". detail::swallow_assign const ignore = detail::swallow_assign(); // --------------------------------------------------------------------------- // 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) { typedef typename detail::make_tuple_mapper::type t; return t(t0); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1) { typedef typename detail::make_tuple_mapper::type t; return t(t0, t1); } template inline typename detail::make_tuple_mapper::type make_tuple(const T0& t0, const T1& t1, const T2& t2) { typedef typename detail::make_tuple_mapper::type t; return t(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) { typedef typename detail::make_tuple_mapper::type t; return t(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) { typedef typename detail::make_tuple_mapper::type t; return t(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) { typedef typename detail::make_tuple_mapper::type t; return t(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) { typedef typename detail::make_tuple_mapper ::type t; return t(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) { typedef typename detail::make_tuple_mapper ::type t; return t(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) { typedef typename detail::make_tuple_mapper ::type t; return t(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) { typedef typename detail::make_tuple_mapper ::type t; return t(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