1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
|
// A very small replacement for boost::tuple
// (c) Alexander Gessler, 2008 [alexander.gessler@gmx.net]
#ifndef BOOST_TUPLE_INCLUDED
#define BOOST_TUPLE_INCLUDED
namespace boost {
namespace detail {
// Represents an empty tuple slot (up to 5 supported)
struct nulltype {};
// For readable error messages
struct tuple_component_idx_out_of_bounds;
// To share some code for the const/nonconst versions of the getters
template <bool b, typename T>
struct ConstIf {
typedef T t;
};
template <typename T>
struct ConstIf<true,T> {
typedef const T t;
};
// Predeclare some stuff
template <typename, unsigned, typename, bool, unsigned> struct value_getter;
// Helper to obtain the type of a tuple element
template <typename T, unsigned NIDX, typename TNEXT, unsigned N /*= 0*/>
struct type_getter {
typedef type_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,N> next_elem_getter;
typedef typename next_elem_getter::type type;
};
template <typename T, unsigned NIDX, typename TNEXT >
struct type_getter <T,NIDX,TNEXT,NIDX> {
typedef T type;
};
// Base class for all explicit specializations of list_elem
template <typename T, unsigned NIDX, typename TNEXT >
struct list_elem_base {
// Store template parameters
typedef TNEXT next_type;
typedef T type;
static const unsigned nidx = NIDX;
};
// Represents an element in the tuple component list
template <typename T, unsigned NIDX, typename TNEXT >
struct list_elem : list_elem_base<T,NIDX,TNEXT>{
// Real members
T me;
TNEXT next;
// Get the value of a specific tuple element
template <unsigned N>
typename type_getter<T,NIDX,TNEXT,N>::type& get () {
value_getter <T,NIDX,TNEXT,false,N> s;
return s(*this);
}
// Get the value of a specific tuple element
template <unsigned N>
const typename type_getter<T,NIDX,TNEXT,N>::type& get () const {
value_getter <T,NIDX,TNEXT,true,N> s;
return s(*this);
}
// Explicit cast
template <typename T2, typename TNEXT2 >
operator list_elem<T2,NIDX,TNEXT2> () const {
list_elem<T2,NIDX,TNEXT2> ret;
ret.me = (T2)me;
ret.next = next;
return ret;
}
// Recursively compare two elements (last element returns always true)
bool operator == (const list_elem& s) const {
return (me == s.me && next == s.next);
}
};
// Represents a non-used tuple element - the very last element processed
template <typename TNEXT, unsigned NIDX >
struct list_elem<nulltype,NIDX,TNEXT> : list_elem_base<nulltype,NIDX,TNEXT> {
template <unsigned N, bool IS_CONST = true> struct value_getter {
/* just dummy members to produce readable error messages */
tuple_component_idx_out_of_bounds operator () (typename ConstIf<IS_CONST,list_elem>::t& me);
};
template <unsigned N> struct type_getter {
/* just dummy members to produce readable error messages */
typedef tuple_component_idx_out_of_bounds type;
};
// dummy
list_elem& operator = (const list_elem& other) {
return *this;
}
// dummy
bool operator == (const list_elem& other) {
return true;
}
};
// Represents the absolute end of the list
typedef list_elem<nulltype,0,int> list_end;
// Helper obtain to query the value of a tuple element
// NOTE: This can't be a nested class as the compiler won't accept a full or
// partial specialization of a nested class of a non-specialized template
template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST, unsigned N>
struct value_getter {
// calling list_elem
typedef list_elem<T,NIDX,TNEXT> outer_elem;
// typedef for the getter for next element
typedef value_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,
IS_CONST, N> next_value_getter;
typename ConstIf<IS_CONST,typename type_getter<T,NIDX,TNEXT,N>::type>::t&
operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
next_value_getter s;
return s(me.next);
}
};
template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST>
struct value_getter <T,NIDX,TNEXT,IS_CONST,NIDX> {
typedef list_elem<T,NIDX,TNEXT> outer_elem;
typename ConstIf<IS_CONST,T>::t& operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
return me.me;
}
};
};
// A very minimal implementation for up to 5 elements
template <typename T0 = detail::nulltype,
typename T1 = detail::nulltype,
typename T2 = detail::nulltype,
typename T3 = detail::nulltype,
typename T4 = detail::nulltype>
class tuple {
template <typename T0b,
typename T1b,
typename T2b,
typename T3b,
typename T4b >
friend class tuple;
private:
typedef detail::list_elem<T0,0,
detail::list_elem<T1,1,
detail::list_elem<T2,2,
detail::list_elem<T3,3,
detail::list_elem<T4,4,
detail::list_end > > > > > very_long;
very_long m;
public:
// Get a specific tuple element
template <unsigned N>
typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () {
return m.template get<N>();
}
// ... and the const version
template <unsigned N>
const typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () const {
return m.template get<N>();
}
// comparison operators
bool operator== (const tuple& other) const {
return m == other.m;
}
// ... and the other way round
bool operator!= (const tuple& other) const {
return !(m == other.m);
}
// cast to another tuple - all single elements must be convertible
template <typename T0b, typename T1b,typename T2b,typename T3b, typename T4b>
operator tuple <T0b,T1b,T2b,T3b,T4b> () const {
tuple <T0b,T1b,T2b,T3b,T4b> s;
s.m = (typename tuple <T0b,T1b,T2b,T3b,T4b>::very_long)m;
return s;
}
};
// Another way to access an element ...
template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
inline typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get (
tuple<T0,T1,T2,T3,T4>& m) {
return m.template get<N>();
}
// ... and the const version
template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
inline const typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get (
const tuple<T0,T1,T2,T3,T4>& m) {
return m.template get<N>();
}
// Constructs a tuple with 5 elements
template <typename T0,typename T1,typename T2,typename T3,typename T4>
inline tuple <T0,T1,T2,T3,T4> make_tuple (const T0& t0,
const T1& t1,const T2& t2,const T3& t3,const T4& t4) {
tuple <T0,T1,T2,T3,T4> t;
t.template get<0>() = t0;
t.template get<1>() = t1;
t.template get<2>() = t2;
t.template get<3>() = t3;
t.template get<4>() = t4;
return t;
}
// Constructs a tuple with 4 elements
template <typename T0,typename T1,typename T2,typename T3>
inline tuple <T0,T1,T2,T3> make_tuple (const T0& t0,
const T1& t1,const T2& t2,const T3& t3) {
tuple <T0,T1,T2,T3> t;
t.template get<0>() = t0;
t.template get<1>() = t1;
t.template get<2>() = t2;
t.template get<3>() = t3;
return t;
}
// Constructs a tuple with 3 elements
template <typename T0,typename T1,typename T2>
inline tuple <T0,T1,T2> make_tuple (const T0& t0,
const T1& t1,const T2& t2) {
tuple <T0,T1,T2> t;
t.template get<0>() = t0;
t.template get<1>() = t1;
t.template get<2>() = t2;
return t;
}
// Constructs a tuple with 2 elements
template <typename T0,typename T1>
inline tuple <T0,T1> make_tuple (const T0& t0,
const T1& t1) {
tuple <T0,T1> t;
t.template get<0>() = t0;
t.template get<1>() = t1;
return t;
}
// Constructs a tuple with 1 elements (well ...)
template <typename T0>
inline tuple <T0> make_tuple (const T0& t0) {
tuple <T0> t;
t.template get<0>() = t0;
return t;
}
// Constructs a tuple with 0 elements (well ...)
inline tuple <> make_tuple () {
tuple <> t = tuple <> ();
return t;
}
};
#endif // !! BOOST_TUPLE_INCLUDED
|