comparison DEPENDENCIES/generic/include/boost/numeric/ublas/traits.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children c530137014c0
comparison
equal deleted inserted replaced
15:663ca0da4350 16:2665513ce2d3
1 //
2 // Copyright (c) 2000-2002
3 // Joerg Walter, Mathias Koch
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // The authors gratefully acknowledge the support of
10 // GeNeSys mbH & Co. KG in producing this work.
11 //
12
13 #ifndef _BOOST_UBLAS_TRAITS_
14 #define _BOOST_UBLAS_TRAITS_
15
16 #include <iterator>
17 #include <complex>
18 #include <boost/config/no_tr1/cmath.hpp>
19
20 #include <boost/numeric/ublas/detail/config.hpp>
21 #include <boost/numeric/ublas/detail/iterator.hpp>
22 #include <boost/numeric/ublas/detail/returntype_deduction.hpp>
23
24 #include <boost/type_traits.hpp>
25 #include <complex>
26 #include <boost/typeof/typeof.hpp>
27 #include <boost/utility/enable_if.hpp>
28 #include <boost/type_traits/is_float.hpp>
29 #include <boost/type_traits/is_integral.hpp>
30 #include <boost/mpl/and.hpp>
31
32 // anonymous namespace to avoid ADL issues
33 namespace {
34 template<class T> T boost_numeric_ublas_sqrt (const T& t) {
35 using namespace std;
36 // we'll find either std::sqrt or else another version via ADL:
37 return sqrt (t);
38 }
39 template<class T> T boost_numeric_ublas_abs (const T& t) {
40 using namespace std;
41 // we'll find either std::abs or else another version via ADL:
42 return abs (t);
43 }
44 // unsigned types are always non-negative
45 template<> unsigned int boost_numeric_ublas_abs (const unsigned int& t) {
46 return t;
47 }
48 // unsigned types are always non-negative
49 template<> unsigned long boost_numeric_ublas_abs (const unsigned long& t) {
50 return t;
51 }
52 }
53
54 namespace boost { namespace numeric { namespace ublas {
55
56 // Use Joel de Guzman's return type deduction
57 // uBLAS assumes a common return type for all binary arithmetic operators
58 template<class X, class Y>
59 struct promote_traits {
60 typedef type_deduction_detail::base_result_of<X, Y> base_type;
61 static typename base_type::x_type x;
62 static typename base_type::y_type y;
63 static const std::size_t size = sizeof (
64 type_deduction_detail::test<
65 typename base_type::x_type
66 , typename base_type::y_type
67 >(x + y) // Use x+y to stand of all the arithmetic actions
68 );
69
70 static const std::size_t index = (size / sizeof (char)) - 1;
71 typedef typename mpl::at_c<
72 typename base_type::types, index>::type id;
73 typedef typename id::type promote_type;
74 };
75
76 template<typename R, typename I>
77 typename boost::enable_if<
78 mpl::and_<
79 boost::is_float<R>,
80 boost::is_integral<I>
81 >,
82 std::complex<R> >::type inline operator+ (I in1, std::complex<R> const& in2 ) {
83 return R (in1) + in2;
84 }
85
86 template<typename R, typename I>
87 typename boost::enable_if<
88 mpl::and_<
89 boost::is_float<R>,
90 boost::is_integral<I>
91 >,
92 std::complex<R> >::type inline operator+ (std::complex<R> const& in1, I in2) {
93 return in1 + R (in2);
94 }
95
96 template<typename R, typename I>
97 typename boost::enable_if<
98 mpl::and_<
99 boost::is_float<R>,
100 boost::is_integral<I>
101 >,
102 std::complex<R> >::type inline operator- (I in1, std::complex<R> const& in2) {
103 return R (in1) - in2;
104 }
105
106 template<typename R, typename I>
107 typename boost::enable_if<
108 mpl::and_<
109 boost::is_float<R>,
110 boost::is_integral<I>
111 >,
112 std::complex<R> >::type inline operator- (std::complex<R> const& in1, I in2) {
113 return in1 - R (in2);
114 }
115
116 template<typename R, typename I>
117 typename boost::enable_if<
118 mpl::and_<
119 boost::is_float<R>,
120 boost::is_integral<I>
121 >,
122 std::complex<R> >::type inline operator* (I in1, std::complex<R> const& in2) {
123 return R (in1) * in2;
124 }
125
126 template<typename R, typename I>
127 typename boost::enable_if<
128 mpl::and_<
129 boost::is_float<R>,
130 boost::is_integral<I>
131 >,
132 std::complex<R> >::type inline operator* (std::complex<R> const& in1, I in2) {
133 return in1 * R(in2);
134 }
135
136 template<typename R, typename I>
137 typename boost::enable_if<
138 mpl::and_<
139 boost::is_float<R>,
140 boost::is_integral<I>
141 >,
142 std::complex<R> >::type inline operator/ (I in1, std::complex<R> const& in2) {
143 return R(in1) / in2;
144 }
145
146 template<typename R, typename I>
147 typename boost::enable_if<
148 mpl::and_<
149 boost::is_float<R>,
150 boost::is_integral<I>
151 >,
152 std::complex<R> >::type inline operator/ (std::complex<R> const& in1, I in2) {
153 return in1 / R (in2);
154 }
155
156
157
158 // Type traits - generic numeric properties and functions
159 template<class T>
160 struct type_traits;
161
162 // Define properties for a generic scalar type
163 template<class T>
164 struct scalar_traits {
165 typedef scalar_traits<T> self_type;
166 typedef T value_type;
167 typedef const T &const_reference;
168 typedef T &reference;
169
170 typedef T real_type;
171 typedef real_type precision_type; // we do not know what type has more precision then the real_type
172
173 static const unsigned plus_complexity = 1;
174 static const unsigned multiplies_complexity = 1;
175
176 static
177 BOOST_UBLAS_INLINE
178 real_type real (const_reference t) {
179 return t;
180 }
181 static
182 BOOST_UBLAS_INLINE
183 real_type imag (const_reference /*t*/) {
184 return 0;
185 }
186 static
187 BOOST_UBLAS_INLINE
188 value_type conj (const_reference t) {
189 return t;
190 }
191
192 static
193 BOOST_UBLAS_INLINE
194 real_type type_abs (const_reference t) {
195 return boost_numeric_ublas_abs (t);
196 }
197 static
198 BOOST_UBLAS_INLINE
199 value_type type_sqrt (const_reference t) {
200 // force a type conversion back to value_type for intgral types
201 return value_type (boost_numeric_ublas_sqrt (t));
202 }
203
204 static
205 BOOST_UBLAS_INLINE
206 real_type norm_1 (const_reference t) {
207 return self_type::type_abs (t);
208 }
209 static
210 BOOST_UBLAS_INLINE
211 real_type norm_2 (const_reference t) {
212 return self_type::type_abs (t);
213 }
214 static
215 BOOST_UBLAS_INLINE
216 real_type norm_inf (const_reference t) {
217 return self_type::type_abs (t);
218 }
219
220 static
221 BOOST_UBLAS_INLINE
222 bool equals (const_reference t1, const_reference t2) {
223 return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
224 (std::max) ((std::max) (self_type::norm_inf (t1),
225 self_type::norm_inf (t2)),
226 BOOST_UBLAS_TYPE_CHECK_MIN);
227 }
228 };
229
230 // Define default type traits, assume T is a scalar type
231 template<class T>
232 struct type_traits : scalar_traits <T> {
233 typedef type_traits<T> self_type;
234 typedef T value_type;
235 typedef const T &const_reference;
236 typedef T &reference;
237
238 typedef T real_type;
239 typedef real_type precision_type;
240 static const unsigned multiplies_complexity = 1;
241
242 };
243
244 // Define real type traits
245 template<>
246 struct type_traits<float> : scalar_traits<float> {
247 typedef type_traits<float> self_type;
248 typedef float value_type;
249 typedef const value_type &const_reference;
250 typedef value_type &reference;
251 typedef value_type real_type;
252 typedef double precision_type;
253 };
254 template<>
255 struct type_traits<double> : scalar_traits<double> {
256 typedef type_traits<double> self_type;
257 typedef double value_type;
258 typedef const value_type &const_reference;
259 typedef value_type &reference;
260 typedef value_type real_type;
261 typedef long double precision_type;
262 };
263 template<>
264 struct type_traits<long double> : scalar_traits<long double> {
265 typedef type_traits<long double> self_type;
266 typedef long double value_type;
267 typedef const value_type &const_reference;
268 typedef value_type &reference;
269 typedef value_type real_type;
270 typedef value_type precision_type;
271 };
272
273 // Define properties for a generic complex type
274 template<class T>
275 struct complex_traits {
276 typedef complex_traits<T> self_type;
277 typedef T value_type;
278 typedef const T &const_reference;
279 typedef T &reference;
280
281 typedef typename T::value_type real_type;
282 typedef real_type precision_type; // we do not know what type has more precision then the real_type
283
284 static const unsigned plus_complexity = 2;
285 static const unsigned multiplies_complexity = 6;
286
287 static
288 BOOST_UBLAS_INLINE
289 real_type real (const_reference t) {
290 return std::real (t);
291 }
292 static
293 BOOST_UBLAS_INLINE
294 real_type imag (const_reference t) {
295 return std::imag (t);
296 }
297 static
298 BOOST_UBLAS_INLINE
299 value_type conj (const_reference t) {
300 return std::conj (t);
301 }
302
303 static
304 BOOST_UBLAS_INLINE
305 real_type type_abs (const_reference t) {
306 return abs (t);
307 }
308 static
309 BOOST_UBLAS_INLINE
310 value_type type_sqrt (const_reference t) {
311 return sqrt (t);
312 }
313
314 static
315 BOOST_UBLAS_INLINE
316 real_type norm_1 (const_reference t) {
317 return self_type::type_abs (t);
318 // original computation has been replaced because a complex number should behave like a scalar type
319 // return type_traits<real_type>::type_abs (self_type::real (t)) +
320 // type_traits<real_type>::type_abs (self_type::imag (t));
321 }
322 static
323 BOOST_UBLAS_INLINE
324 real_type norm_2 (const_reference t) {
325 return self_type::type_abs (t);
326 }
327 static
328 BOOST_UBLAS_INLINE
329 real_type norm_inf (const_reference t) {
330 return self_type::type_abs (t);
331 // original computation has been replaced because a complex number should behave like a scalar type
332 // return (std::max) (type_traits<real_type>::type_abs (self_type::real (t)),
333 // type_traits<real_type>::type_abs (self_type::imag (t)));
334 }
335
336 static
337 BOOST_UBLAS_INLINE
338 bool equals (const_reference t1, const_reference t2) {
339 return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
340 (std::max) ((std::max) (self_type::norm_inf (t1),
341 self_type::norm_inf (t2)),
342 BOOST_UBLAS_TYPE_CHECK_MIN);
343 }
344 };
345
346 // Define complex type traits
347 template<>
348 struct type_traits<std::complex<float> > : complex_traits<std::complex<float> >{
349 typedef type_traits<std::complex<float> > self_type;
350 typedef std::complex<float> value_type;
351 typedef const value_type &const_reference;
352 typedef value_type &reference;
353 typedef float real_type;
354 typedef std::complex<double> precision_type;
355
356 };
357 template<>
358 struct type_traits<std::complex<double> > : complex_traits<std::complex<double> >{
359 typedef type_traits<std::complex<double> > self_type;
360 typedef std::complex<double> value_type;
361 typedef const value_type &const_reference;
362 typedef value_type &reference;
363 typedef double real_type;
364 typedef std::complex<long double> precision_type;
365 };
366 template<>
367 struct type_traits<std::complex<long double> > : complex_traits<std::complex<long double> > {
368 typedef type_traits<std::complex<long double> > self_type;
369 typedef std::complex<long double> value_type;
370 typedef const value_type &const_reference;
371 typedef value_type &reference;
372 typedef long double real_type;
373 typedef value_type precision_type;
374 };
375
376 #ifdef BOOST_UBLAS_USE_INTERVAL
377 // Define scalar interval type traits
378 template<>
379 struct type_traits<boost::numeric::interval<float> > : scalar_traits<boost::numeric::interval<float> > {
380 typedef type_traits<boost::numeric::interval<float> > self_type;
381 typedef boost::numeric::interval<float> value_type;
382 typedef const value_type &const_reference;
383 typedef value_type &reference;
384 typedef value_type real_type;
385 typedef boost::numeric::interval<double> precision_type;
386
387 };
388 template<>
389 struct type_traits<boost::numeric::interval<double> > : scalar_traits<boost::numeric::interval<double> > {
390 typedef type_traits<boost::numeric::interval<double> > self_type;
391 typedef boost::numeric::interval<double> value_type;
392 typedef const value_type &const_reference;
393 typedef value_type &reference;
394 typedef value_type real_type;
395 typedef boost::numeric::interval<long double> precision_type;
396 };
397 template<>
398 struct type_traits<boost::numeric::interval<long double> > : scalar_traits<boost::numeric::interval<long double> > {
399 typedef type_traits<boost::numeric::interval<long double> > self_type;
400 typedef boost::numeric::interval<long double> value_type;
401 typedef const value_type &const_reference;
402 typedef value_type &reference;
403 typedef value_type real_type;
404 typedef value_type precision_type;
405 };
406 #endif
407
408
409 // Storage tags -- hierarchical definition of storage characteristics
410
411 struct unknown_storage_tag {};
412 struct sparse_proxy_tag: public unknown_storage_tag {};
413 struct sparse_tag: public sparse_proxy_tag {};
414 struct packed_proxy_tag: public sparse_proxy_tag {};
415 struct packed_tag: public packed_proxy_tag {};
416 struct dense_proxy_tag: public packed_proxy_tag {};
417 struct dense_tag: public dense_proxy_tag {};
418
419 template<class S1, class S2>
420 struct storage_restrict_traits {
421 typedef S1 storage_category;
422 };
423
424 template<>
425 struct storage_restrict_traits<sparse_tag, dense_proxy_tag> {
426 typedef sparse_proxy_tag storage_category;
427 };
428 template<>
429 struct storage_restrict_traits<sparse_tag, packed_proxy_tag> {
430 typedef sparse_proxy_tag storage_category;
431 };
432 template<>
433 struct storage_restrict_traits<sparse_tag, sparse_proxy_tag> {
434 typedef sparse_proxy_tag storage_category;
435 };
436
437 template<>
438 struct storage_restrict_traits<packed_tag, dense_proxy_tag> {
439 typedef packed_proxy_tag storage_category;
440 };
441 template<>
442 struct storage_restrict_traits<packed_tag, packed_proxy_tag> {
443 typedef packed_proxy_tag storage_category;
444 };
445 template<>
446 struct storage_restrict_traits<packed_tag, sparse_proxy_tag> {
447 typedef sparse_proxy_tag storage_category;
448 };
449
450 template<>
451 struct storage_restrict_traits<packed_proxy_tag, sparse_proxy_tag> {
452 typedef sparse_proxy_tag storage_category;
453 };
454
455 template<>
456 struct storage_restrict_traits<dense_tag, dense_proxy_tag> {
457 typedef dense_proxy_tag storage_category;
458 };
459 template<>
460 struct storage_restrict_traits<dense_tag, packed_proxy_tag> {
461 typedef packed_proxy_tag storage_category;
462 };
463 template<>
464 struct storage_restrict_traits<dense_tag, sparse_proxy_tag> {
465 typedef sparse_proxy_tag storage_category;
466 };
467
468 template<>
469 struct storage_restrict_traits<dense_proxy_tag, packed_proxy_tag> {
470 typedef packed_proxy_tag storage_category;
471 };
472 template<>
473 struct storage_restrict_traits<dense_proxy_tag, sparse_proxy_tag> {
474 typedef sparse_proxy_tag storage_category;
475 };
476
477
478 // Iterator tags -- hierarchical definition of storage characteristics
479
480 struct sparse_bidirectional_iterator_tag : public std::bidirectional_iterator_tag {};
481 struct packed_random_access_iterator_tag : public std::random_access_iterator_tag {};
482 struct dense_random_access_iterator_tag : public packed_random_access_iterator_tag {};
483
484 // Thanks to Kresimir Fresl for convincing Comeau with iterator_base_traits ;-)
485 template<class IC>
486 struct iterator_base_traits {};
487
488 template<>
489 struct iterator_base_traits<std::forward_iterator_tag> {
490 template<class I, class T>
491 struct iterator_base {
492 typedef forward_iterator_base<std::forward_iterator_tag, I, T> type;
493 };
494 };
495
496 template<>
497 struct iterator_base_traits<std::bidirectional_iterator_tag> {
498 template<class I, class T>
499 struct iterator_base {
500 typedef bidirectional_iterator_base<std::bidirectional_iterator_tag, I, T> type;
501 };
502 };
503 template<>
504 struct iterator_base_traits<sparse_bidirectional_iterator_tag> {
505 template<class I, class T>
506 struct iterator_base {
507 typedef bidirectional_iterator_base<sparse_bidirectional_iterator_tag, I, T> type;
508 };
509 };
510
511 template<>
512 struct iterator_base_traits<std::random_access_iterator_tag> {
513 template<class I, class T>
514 struct iterator_base {
515 typedef random_access_iterator_base<std::random_access_iterator_tag, I, T> type;
516 };
517 };
518 template<>
519 struct iterator_base_traits<packed_random_access_iterator_tag> {
520 template<class I, class T>
521 struct iterator_base {
522 typedef random_access_iterator_base<packed_random_access_iterator_tag, I, T> type;
523 };
524 };
525 template<>
526 struct iterator_base_traits<dense_random_access_iterator_tag> {
527 template<class I, class T>
528 struct iterator_base {
529 typedef random_access_iterator_base<dense_random_access_iterator_tag, I, T> type;
530 };
531 };
532
533 template<class I1, class I2>
534 struct iterator_restrict_traits {
535 typedef I1 iterator_category;
536 };
537
538 template<>
539 struct iterator_restrict_traits<packed_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
540 typedef sparse_bidirectional_iterator_tag iterator_category;
541 };
542 template<>
543 struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, packed_random_access_iterator_tag> {
544 typedef sparse_bidirectional_iterator_tag iterator_category;
545 };
546
547 template<>
548 struct iterator_restrict_traits<dense_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
549 typedef sparse_bidirectional_iterator_tag iterator_category;
550 };
551 template<>
552 struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, dense_random_access_iterator_tag> {
553 typedef sparse_bidirectional_iterator_tag iterator_category;
554 };
555
556 template<>
557 struct iterator_restrict_traits<dense_random_access_iterator_tag, packed_random_access_iterator_tag> {
558 typedef packed_random_access_iterator_tag iterator_category;
559 };
560 template<>
561 struct iterator_restrict_traits<packed_random_access_iterator_tag, dense_random_access_iterator_tag> {
562 typedef packed_random_access_iterator_tag iterator_category;
563 };
564
565 template<class I>
566 BOOST_UBLAS_INLINE
567 void increment (I &it, const I &it_end, typename I::difference_type compare, packed_random_access_iterator_tag) {
568 it += (std::min) (compare, it_end - it);
569 }
570 template<class I>
571 BOOST_UBLAS_INLINE
572 void increment (I &it, const I &/* it_end */, typename I::difference_type /* compare */, sparse_bidirectional_iterator_tag) {
573 ++ it;
574 }
575 template<class I>
576 BOOST_UBLAS_INLINE
577 void increment (I &it, const I &it_end, typename I::difference_type compare) {
578 increment (it, it_end, compare, typename I::iterator_category ());
579 }
580
581 template<class I>
582 BOOST_UBLAS_INLINE
583 void increment (I &it, const I &it_end) {
584 #if BOOST_UBLAS_TYPE_CHECK
585 I cit (it);
586 while (cit != it_end) {
587 BOOST_UBLAS_CHECK (*cit == typename I::value_type/*zero*/(), internal_logic ());
588 ++ cit;
589 }
590 #endif
591 it = it_end;
592 }
593
594 namespace detail {
595
596 // specialisation which define whether a type has a trivial constructor
597 // or not. This is used by array types.
598 template<typename T>
599 struct has_trivial_constructor : public boost::has_trivial_constructor<T> {};
600
601 template<typename T>
602 struct has_trivial_destructor : public boost::has_trivial_destructor<T> {};
603
604 template<typename FLT>
605 struct has_trivial_constructor<std::complex<FLT> > : public has_trivial_constructor<FLT> {};
606
607 template<typename FLT>
608 struct has_trivial_destructor<std::complex<FLT> > : public has_trivial_destructor<FLT> {};
609
610 }
611
612
613 /** \brief Traits class to extract type information from a constant matrix or vector CONTAINER.
614 *
615 */
616 template < class E >
617 struct container_view_traits {
618 /// type of indices
619 typedef typename E::size_type size_type;
620 /// type of differences of indices
621 typedef typename E::difference_type difference_type;
622
623 /// storage category: \c unknown_storage_tag, \c dense_tag, \c packed_tag, ...
624 typedef typename E::storage_category storage_category;
625
626 /// type of elements
627 typedef typename E::value_type value_type;
628 /// const reference to an element
629 typedef typename E::const_reference const_reference;
630
631 /// type used in expressions to mark a reference to this class (usually a const container_reference<const E> or the class itself)
632 typedef typename E::const_closure_type const_closure_type;
633 };
634
635 /** \brief Traits class to extract additional type information from a mutable matrix or vector CONTAINER.
636 *
637 */
638 template < class E >
639 struct mutable_container_traits {
640 /// reference to an element
641 typedef typename E::reference reference;
642
643 /// type used in expressions to mark a reference to this class (usually a container_reference<E> or the class itself)
644 typedef typename E::closure_type closure_type;
645 };
646
647 /** \brief Traits class to extract type information from a matrix or vector CONTAINER.
648 *
649 */
650 template < class E >
651 struct container_traits
652 : container_view_traits<E>, mutable_container_traits<E> {
653
654 };
655
656
657 /** \brief Traits class to extract type information from a constant MATRIX.
658 *
659 */
660 template < class MATRIX >
661 struct matrix_view_traits : container_view_traits <MATRIX> {
662
663 /// orientation of the matrix, either \c row_major_tag, \c column_major_tag or \c unknown_orientation_tag
664 typedef typename MATRIX::orientation_category orientation_category;
665
666 /// row iterator for the matrix
667 typedef typename MATRIX::const_iterator1 const_iterator1;
668
669 /// column iterator for the matrix
670 typedef typename MATRIX::const_iterator2 const_iterator2;
671 };
672
673 /** \brief Traits class to extract additional type information from a mutable MATRIX.
674 *
675 */
676 template < class MATRIX >
677 struct mutable_matrix_traits
678 : mutable_container_traits <MATRIX> {
679
680 /// row iterator for the matrix
681 typedef typename MATRIX::iterator1 iterator1;
682
683 /// column iterator for the matrix
684 typedef typename MATRIX::iterator2 iterator2;
685 };
686
687
688 /** \brief Traits class to extract type information from a MATRIX.
689 *
690 */
691 template < class MATRIX >
692 struct matrix_traits
693 : matrix_view_traits <MATRIX>, mutable_matrix_traits <MATRIX> {
694 };
695
696 /** \brief Traits class to extract type information from a VECTOR.
697 *
698 */
699 template < class VECTOR >
700 struct vector_view_traits : container_view_traits <VECTOR> {
701
702 /// iterator for the VECTOR
703 typedef typename VECTOR::const_iterator const_iterator;
704
705 /// iterator pointing to the first element
706 static
707 const_iterator begin(const VECTOR & v) {
708 return v.begin();
709 }
710 /// iterator pointing behind the last element
711 static
712 const_iterator end(const VECTOR & v) {
713 return v.end();
714 }
715
716 };
717
718 /** \brief Traits class to extract type information from a VECTOR.
719 *
720 */
721 template < class VECTOR >
722 struct mutable_vector_traits : mutable_container_traits <VECTOR> {
723 /// iterator for the VECTOR
724 typedef typename VECTOR::iterator iterator;
725
726 /// iterator pointing to the first element
727 static
728 iterator begin(VECTOR & v) {
729 return v.begin();
730 }
731
732 /// iterator pointing behind the last element
733 static
734 iterator end(VECTOR & v) {
735 return v.end();
736 }
737 };
738
739 /** \brief Traits class to extract type information from a VECTOR.
740 *
741 */
742 template < class VECTOR >
743 struct vector_traits
744 : vector_view_traits <VECTOR>, mutable_vector_traits <VECTOR> {
745 };
746
747
748 // Note: specializations for T[N] and T[M][N] have been moved to traits/c_array.hpp
749
750 }}}
751
752 #endif