tuple.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // A very small replacement for boost::tuple
  2. // (c) Alexander Gessler, 2008
  3. #ifndef BOOST_TUPLE_INCLUDED
  4. #define BOOST_TUPLE_INCLUDED
  5. namespace boost {
  6. namespace detail {
  7. // Represents an empty tuple slot (up to 5 supported)
  8. struct nulltype {};
  9. // For readable error messages
  10. struct tuple_component_idx_out_of_bounds;
  11. // To share some code for the const/nonconst versions of the getters
  12. template <bool b, typename T>
  13. struct ConstIf {
  14. typedef T t;
  15. };
  16. template <typename T>
  17. struct ConstIf<true,T> {
  18. typedef const T t;
  19. };
  20. template <typename, unsigned, typename, bool, unsigned>
  21. struct value_getter;
  22. template <typename T, unsigned NIDX, typename TNEXT >
  23. struct list_elem_base {
  24. // Store template parameters
  25. typedef TNEXT next_type;
  26. typedef T type;
  27. static const unsigned nidx = NIDX;
  28. };
  29. // Represents an element in the tuple component list
  30. template <typename T, unsigned NIDX, typename TNEXT >
  31. struct list_elem : list_elem_base<T,NIDX,TNEXT>{
  32. // Real members
  33. T me;
  34. TNEXT next;
  35. // Get the value of a specific tuple element
  36. template <unsigned N>
  37. T& get () {
  38. value_getter <T,NIDX,TNEXT,false,N> s;
  39. return s(*this);
  40. }
  41. // Get the value of a specific tuple element
  42. template <unsigned N>
  43. const T& get () const {
  44. value_getter <T,NIDX,TNEXT,true,N> s;
  45. return s(*this);
  46. }
  47. // Assign a value to the tuple element
  48. template <typename T2, typename TNEXT2> /* requires convertible(T2,T) */
  49. list_elem& operator = (const list_elem<T2,NIDX,TNEXT2>& other) {
  50. me = (T)other.me;
  51. next = other.next;
  52. return *this;
  53. }
  54. // Recursively compare two elements
  55. bool operator == (const list_elem& s) const {
  56. return (me == s.me && next == s.next);
  57. }
  58. };
  59. // Represents a non-used tuple element - the very last element processed
  60. template <typename TNEXT, unsigned NIDX >
  61. struct list_elem<nulltype,NIDX,TNEXT> : list_elem_base<nulltype,NIDX,TNEXT> {
  62. template <unsigned N, bool IS_CONST = true> struct value_getter {
  63. /* just dummy members to produce readable error messages */
  64. tuple_component_idx_out_of_bounds operator () (typename ConstIf<IS_CONST,list_elem>::t& me);
  65. };
  66. template <unsigned N> struct type_getter {
  67. /* just dummy members to produce readable error messages */
  68. typedef tuple_component_idx_out_of_bounds type;
  69. };
  70. // dummy
  71. list_elem& operator = (const list_elem& other) {
  72. return *this;
  73. }
  74. // dummy
  75. bool operator == (const list_elem& other) {
  76. return true;
  77. }
  78. };
  79. // Represents the absolute end of the list
  80. typedef list_elem<nulltype,0,int> list_end;
  81. // Helper obtain to query the value of a tuple element
  82. // NOTE: Could be a nested class, but afaik it's non-standard and at least
  83. // MSVC isn't able to evaluate the partial specialization correctly.
  84. template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST, unsigned N>
  85. struct value_getter {
  86. // calling list_elem
  87. typedef list_elem<T,NIDX,TNEXT> outer_elem;
  88. // typedef for the getter for next element
  89. typedef value_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,
  90. IS_CONST, N> next_value_getter;
  91. typename ConstIf<IS_CONST,T>::t& operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
  92. next_value_getter s;
  93. return s(me.next);
  94. }
  95. };
  96. template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST>
  97. struct value_getter <T,NIDX,TNEXT,IS_CONST,NIDX> {
  98. typedef list_elem<T,NIDX,TNEXT> outer_elem;
  99. typename ConstIf<IS_CONST,T>::t& operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
  100. return me.me;
  101. }
  102. };
  103. // Helper to obtain the type of a tuple element
  104. template <typename T, unsigned NIDX, typename TNEXT, unsigned N /*= 0*/>
  105. struct type_getter {
  106. typedef type_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,N> next_elem_getter;
  107. typedef typename next_elem_getter::type type;
  108. };
  109. template <typename T, unsigned NIDX, typename TNEXT >
  110. struct type_getter <T,NIDX,TNEXT,NIDX> {
  111. typedef T type;
  112. };
  113. };
  114. // A very minimal implementation for up to 5 elements
  115. template <typename T0 = detail::nulltype,
  116. typename T1 = detail::nulltype,
  117. typename T2 = detail::nulltype,
  118. typename T3 = detail::nulltype,
  119. typename T4 = detail::nulltype>
  120. class tuple {
  121. friend class tuple;
  122. private:
  123. typedef detail::list_elem<T0,0,
  124. detail::list_elem<T1,1,
  125. detail::list_elem<T2,2,
  126. detail::list_elem<T3,3,
  127. detail::list_elem<T4,4,
  128. detail::list_end > > > > > very_long;
  129. very_long m;
  130. public:
  131. // Get a specific tuple element
  132. template <unsigned N>
  133. typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () {
  134. return m.get<N>();
  135. }
  136. // ... and the const version
  137. template <unsigned N>
  138. typename const detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () const {
  139. return m.get<N>();
  140. }
  141. // assignment operator
  142. tuple& operator= (const tuple& other) {
  143. m = other.m;
  144. return *this;
  145. }
  146. // comparison operators
  147. bool operator== (const tuple& other) const {
  148. return m == other.m;
  149. }
  150. // ... and the other way round
  151. bool operator!= (const tuple& other) const {
  152. return !(m == other.m);
  153. }
  154. // cast to another tuple - all single elements must be convertible
  155. template < typename T0, typename T1,typename T2,
  156. typename T3, typename T4>
  157. operator tuple <T0,T1,T2,T3,T4> () {
  158. tuple <T0,T1,T2,T3,T4> s;
  159. s.m = m;
  160. return s;
  161. }
  162. };
  163. // Another way to access an element ...
  164. template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
  165. inline typename tuple<T0,T1,T2,T3,T4>::very_long::type_getter<N>::type& get (
  166. tuple<T0,T1,T2,T3,T4>& m) {
  167. return m.get<N>();
  168. }
  169. // ... and the const version
  170. template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
  171. inline const typename tuple<T0,T1,T2,T3,T4>::very_long::type_getter<N>::type& get (
  172. const tuple<T0,T1,T2,T3,T4>& m) {
  173. return m.get<N>();
  174. }
  175. // Constructs a tuple with 5 elements
  176. template <typename T0,typename T1,typename T2,typename T3,typename T4>
  177. inline tuple <T0,T1,T2,T3,T4> make_tuple (const T0& t0,
  178. const T1& t1,const T2& t2,const T3& t3,const T4& t4) {
  179. tuple <T0,T1,T2,T3,T4> t;
  180. t.get<0>() = t0;
  181. t.get<1>() = t1;
  182. t.get<2>() = t2;
  183. t.get<3>() = t3;
  184. t.get<4>() = t4;
  185. return t;
  186. }
  187. // Constructs a tuple with 4 elements
  188. template <typename T0,typename T1,typename T2,typename T3>
  189. inline tuple <T0,T1,T2,T3> make_tuple (const T0& t0,
  190. const T1& t1,const T2& t2,const T3& t3) {
  191. tuple <T0,T1,T2,T3> t;
  192. t.get<0>() = t0;
  193. t.get<1>() = t1;
  194. t.get<2>() = t2;
  195. t.get<3>() = t3;
  196. return t;
  197. }
  198. // Constructs a tuple with 3 elements
  199. template <typename T0,typename T1,typename T2>
  200. inline tuple <T0,T1,T2> make_tuple (const T0& t0,
  201. const T1& t1,const T2& t2) {
  202. tuple <T0,T1,T2> t;
  203. t.get<0>() = t0;
  204. t.get<1>() = t1;
  205. t.get<2>() = t2;
  206. return t;
  207. }
  208. // Constructs a tuple with 2 elements (fucking idiot, use std::pair instead!)
  209. template <typename T0,typename T1>
  210. inline tuple <T0,T1> make_tuple (const T0& t0,
  211. const T1& t1) {
  212. tuple <T0,T1> t;
  213. t.get<0>() = t0;
  214. t.get<1>() = t1;
  215. return t;
  216. }
  217. // Constructs a tuple with 1 elements (no comment ...)
  218. template <typename T0>
  219. inline tuple <T0> make_tuple (const T0& t0) {
  220. tuple <T0> t;
  221. t.get<0>() = t0;
  222. return t;
  223. }
  224. // Constructs a tuple with 0 elements (ehm? Try http://www.promillerechner.net)
  225. inline tuple <> make_tuple () {
  226. tuple <> t;
  227. return t;
  228. }
  229. };
  230. #endif