Boost.uBlas 1.49
Linear Algebra in C++: matrices, vectors and numeric algorithms

traits.hpp

Go to the documentation of this file.
00001 //
00002 //  Copyright (c) 2000-2002
00003 //  Joerg Walter, Mathias Koch
00004 //
00005 //  Distributed under the Boost Software License, Version 1.0. (See
00006 //  accompanying file LICENSE_1_0.txt or copy at
00007 //  http://www.boost.org/LICENSE_1_0.txt)
00008 //
00009 //  The authors gratefully acknowledge the support of
00010 //  GeNeSys mbH & Co. KG in producing this work.
00011 //
00012 
00013 #ifndef _BOOST_UBLAS_TRAITS_
00014 #define _BOOST_UBLAS_TRAITS_
00015 
00016 #include <iterator>
00017 #include <complex>
00018 #include <boost/config/no_tr1/cmath.hpp>
00019 
00020 #include <boost/numeric/ublas/detail/config.hpp>
00021 #include <boost/numeric/ublas/detail/iterator.hpp>
00022 #include <boost/numeric/ublas/detail/returntype_deduction.hpp>
00023 
00024 #include <boost/type_traits.hpp>
00025 #include <complex>
00026 #include <boost/typeof/typeof.hpp>
00027 #include <boost/utility/enable_if.hpp>
00028 #include <boost/type_traits/is_float.hpp>
00029 #include <boost/type_traits/is_integral.hpp>
00030 #include <boost/mpl/and.hpp>
00031 
00032 // anonymous namespace to avoid ADL issues
00033 namespace {
00034   template<class T> T boost_numeric_ublas_sqrt (const T& t) {
00035     using namespace std;
00036     // we'll find either std::sqrt or else another version via ADL:
00037     return sqrt (t);
00038   }
00039   template<class T> T boost_numeric_ublas_abs (const T& t) {
00040     using namespace std;
00041     // we'll find either std::abs or else another version via ADL:
00042     return abs (t);
00043   }
00044 }
00045 
00046 namespace boost { namespace numeric { namespace ublas {
00047 
00048     // Use Joel de Guzman's return type deduction
00049     // uBLAS assumes a common return type for all binary arithmetic operators
00050     template<class X, class Y>
00051     struct promote_traits {
00052         typedef type_deduction_detail::base_result_of<X, Y> base_type;
00053         static typename base_type::x_type x;
00054         static typename base_type::y_type y;
00055         static const std::size_t size = sizeof (
00056                 type_deduction_detail::test<
00057                     typename base_type::x_type
00058                   , typename base_type::y_type
00059                 >(x + y)     // Use x+y to stand of all the arithmetic actions
00060             );
00061 
00062         static const std::size_t index = (size / sizeof (char)) - 1;
00063         typedef typename mpl::at_c<
00064             typename base_type::types, index>::type id;
00065         typedef typename id::type promote_type;
00066     };
00067 
00068       template<typename R, typename I> 
00069       typename boost::enable_if<
00070         mpl::and_<
00071           boost::is_float<R>,
00072           boost::is_integral<I>
00073           >,
00074         std::complex<R> >::type inline operator+ (I in1, std::complex<R> const& in2 ) {
00075         return R (in1) + in2;
00076       }
00077 
00078       template<typename R, typename I> 
00079       typename boost::enable_if<
00080         mpl::and_<
00081           boost::is_float<R>,
00082           boost::is_integral<I>
00083           >,
00084         std::complex<R> >::type inline operator+ (std::complex<R> const& in1, I in2) {
00085         return in1 + R (in2);
00086       }
00087 
00088       template<typename R, typename I> 
00089       typename boost::enable_if<
00090         mpl::and_<
00091           boost::is_float<R>,
00092           boost::is_integral<I>
00093           >,
00094         std::complex<R> >::type inline operator- (I in1, std::complex<R> const& in2) {
00095         return R (in1) - in2;
00096       }
00097 
00098       template<typename R, typename I> 
00099       typename boost::enable_if<
00100         mpl::and_<
00101           boost::is_float<R>,
00102           boost::is_integral<I>
00103           >,
00104         std::complex<R> >::type inline operator- (std::complex<R> const& in1, I in2) {
00105         return in1 - R (in2);
00106       }
00107 
00108       template<typename R, typename I> 
00109       typename boost::enable_if<
00110         mpl::and_<
00111           boost::is_float<R>,
00112           boost::is_integral<I>
00113           >,
00114         std::complex<R> >::type inline operator* (I in1, std::complex<R> const& in2) {
00115         return R (in1) * in2;
00116       }
00117 
00118       template<typename R, typename I> 
00119       typename boost::enable_if<
00120         mpl::and_<
00121           boost::is_float<R>,
00122           boost::is_integral<I>
00123           >,
00124         std::complex<R> >::type inline operator* (std::complex<R> const& in1, I in2) {
00125         return in1 * R(in2);
00126       }
00127 
00128       template<typename R, typename I> 
00129       typename boost::enable_if<
00130         mpl::and_<
00131           boost::is_float<R>,
00132           boost::is_integral<I>
00133           >,
00134         std::complex<R> >::type inline operator/ (I in1, std::complex<R> const& in2) {
00135         return R(in1) / in2;
00136       }
00137 
00138       template<typename R, typename I> 
00139       typename boost::enable_if<
00140         mpl::and_<
00141           boost::is_float<R>,
00142           boost::is_integral<I>
00143           >,
00144         std::complex<R> >::type inline operator/ (std::complex<R> const& in1, I in2) {
00145         return in1 / R (in2);
00146       }
00147 
00148 
00149 
00150     // Type traits - generic numeric properties and functions
00151     template<class T>
00152     struct type_traits;
00153         
00154     // Define properties for a generic scalar type
00155     template<class T>
00156     struct scalar_traits {
00157         typedef scalar_traits<T> self_type;
00158         typedef T value_type;
00159         typedef const T &const_reference;
00160         typedef T &reference;
00161 
00162         typedef T real_type;
00163         typedef real_type precision_type;       // we do not know what type has more precision then the real_type
00164 
00165         static const unsigned plus_complexity = 1;
00166         static const unsigned multiplies_complexity = 1;
00167 
00168         static
00169         BOOST_UBLAS_INLINE
00170         real_type real (const_reference t) {
00171                 return t;
00172         }
00173         static
00174         BOOST_UBLAS_INLINE
00175         real_type imag (const_reference /*t*/) {
00176                 return 0;
00177         }
00178         static
00179         BOOST_UBLAS_INLINE
00180         value_type conj (const_reference t) {
00181                 return t;
00182         }
00183 
00184         static
00185         BOOST_UBLAS_INLINE
00186         real_type type_abs (const_reference t) {
00187             return boost_numeric_ublas_abs (t);
00188         }
00189         static
00190         BOOST_UBLAS_INLINE
00191         value_type type_sqrt (const_reference t) {
00192             // force a type conversion back to value_type for intgral types
00193             return value_type (boost_numeric_ublas_sqrt (t));
00194         }
00195 
00196         static
00197         BOOST_UBLAS_INLINE
00198         real_type norm_1 (const_reference t) {
00199             return self_type::type_abs (t);
00200         }
00201         static
00202         BOOST_UBLAS_INLINE
00203         real_type norm_2 (const_reference t) {
00204             return self_type::type_abs (t);
00205         }
00206         static
00207         BOOST_UBLAS_INLINE
00208         real_type norm_inf (const_reference t) {
00209             return self_type::type_abs (t);
00210         }
00211 
00212         static
00213         BOOST_UBLAS_INLINE
00214         bool equals (const_reference t1, const_reference t2) {
00215             return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
00216                    (std::max) ((std::max) (self_type::norm_inf (t1),
00217                                        self_type::norm_inf (t2)),
00218                              BOOST_UBLAS_TYPE_CHECK_MIN);
00219         }
00220     };
00221 
00222     // Define default type traits, assume T is a scalar type
00223     template<class T>
00224     struct type_traits : scalar_traits <T> {
00225         typedef type_traits<T> self_type;
00226         typedef T value_type;
00227         typedef const T &const_reference;
00228         typedef T &reference;
00229 
00230         typedef T real_type;
00231         typedef real_type precision_type;
00232         static const unsigned multiplies_complexity = 1;
00233 
00234     };
00235 
00236     // Define real type traits
00237     template<>
00238     struct type_traits<float> : scalar_traits<float> {
00239         typedef type_traits<float> self_type;
00240         typedef float value_type;
00241         typedef const value_type &const_reference;
00242         typedef value_type &reference;
00243         typedef value_type real_type;
00244         typedef double precision_type;
00245     };
00246     template<>
00247     struct type_traits<double> : scalar_traits<double> {
00248         typedef type_traits<double> self_type;
00249         typedef double value_type;
00250         typedef const value_type &const_reference;
00251         typedef value_type &reference;
00252         typedef value_type real_type;
00253         typedef long double precision_type;
00254     };
00255     template<>
00256     struct type_traits<long double>  : scalar_traits<long double> {
00257         typedef type_traits<long double> self_type;
00258         typedef long double value_type;
00259         typedef const value_type &const_reference;
00260         typedef value_type &reference;
00261         typedef value_type real_type;
00262         typedef value_type precision_type;
00263     };
00264 
00265     // Define properties for a generic complex type
00266     template<class T>
00267     struct complex_traits {
00268         typedef complex_traits<T> self_type;
00269         typedef T value_type;
00270         typedef const T &const_reference;
00271         typedef T &reference;
00272 
00273         typedef typename T::value_type real_type;
00274         typedef real_type precision_type;       // we do not know what type has more precision then the real_type
00275 
00276         static const unsigned plus_complexity = 2;
00277         static const unsigned multiplies_complexity = 6;
00278 
00279         static
00280         BOOST_UBLAS_INLINE
00281         real_type real (const_reference t) {
00282                 return std::real (t);
00283         }
00284         static
00285         BOOST_UBLAS_INLINE
00286         real_type imag (const_reference t) {
00287                 return std::imag (t);
00288         }
00289         static
00290         BOOST_UBLAS_INLINE
00291         value_type conj (const_reference t) {
00292                 return std::conj (t);
00293         }
00294 
00295         static
00296         BOOST_UBLAS_INLINE
00297         real_type type_abs (const_reference t) {
00298                 return abs (t);
00299         }
00300         static
00301         BOOST_UBLAS_INLINE
00302         value_type type_sqrt (const_reference t) {
00303                 return sqrt (t);
00304         }
00305 
00306         static
00307         BOOST_UBLAS_INLINE
00308         real_type norm_1 (const_reference t) {
00309             return self_type::type_abs (t);
00310             // original computation has been replaced because a complex number should behave like a scalar type
00311             // return type_traits<real_type>::type_abs (self_type::real (t)) +
00312             //       type_traits<real_type>::type_abs (self_type::imag (t));
00313         }
00314         static
00315         BOOST_UBLAS_INLINE
00316         real_type norm_2 (const_reference t) {
00317             return self_type::type_abs (t);
00318         }
00319         static
00320         BOOST_UBLAS_INLINE
00321         real_type norm_inf (const_reference t) {
00322             return self_type::type_abs (t);
00323             // original computation has been replaced because a complex number should behave like a scalar type
00324             // return (std::max) (type_traits<real_type>::type_abs (self_type::real (t)),
00325             //                 type_traits<real_type>::type_abs (self_type::imag (t)));
00326         }
00327 
00328         static
00329         BOOST_UBLAS_INLINE
00330         bool equals (const_reference t1, const_reference t2) {
00331             return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
00332                    (std::max) ((std::max) (self_type::norm_inf (t1),
00333                                        self_type::norm_inf (t2)),
00334                              BOOST_UBLAS_TYPE_CHECK_MIN);
00335         }
00336     };
00337     
00338     // Define complex type traits
00339     template<>
00340     struct type_traits<std::complex<float> > : complex_traits<std::complex<float> >{
00341         typedef type_traits<std::complex<float> > self_type;
00342         typedef std::complex<float> value_type;
00343         typedef const value_type &const_reference;
00344         typedef value_type &reference;
00345         typedef float real_type;
00346         typedef std::complex<double> precision_type;
00347 
00348     };
00349     template<>
00350     struct type_traits<std::complex<double> > : complex_traits<std::complex<double> >{
00351         typedef type_traits<std::complex<double> > self_type;
00352         typedef std::complex<double> value_type;
00353         typedef const value_type &const_reference;
00354         typedef value_type &reference;
00355         typedef double real_type;
00356         typedef std::complex<long double> precision_type;
00357     };
00358     template<>
00359     struct type_traits<std::complex<long double> > : complex_traits<std::complex<long double> > {
00360         typedef type_traits<std::complex<long double> > self_type;
00361         typedef std::complex<long double> value_type;
00362         typedef const value_type &const_reference;
00363         typedef value_type &reference;
00364         typedef long double real_type;
00365         typedef value_type precision_type;
00366     };
00367 
00368 #ifdef BOOST_UBLAS_USE_INTERVAL
00369     // Define scalar interval type traits
00370     template<>
00371     struct type_traits<boost::numeric::interval<float> > : scalar_traits<boost::numeric::interval<float> > {
00372         typedef type_traits<boost::numeric::interval<float> > self_type;
00373         typedef boost::numeric::interval<float> value_type;
00374         typedef const value_type &const_reference;
00375         typedef value_type &reference;
00376         typedef value_type real_type;
00377         typedef boost::numeric::interval<double> precision_type;
00378 
00379     };
00380     template<>
00381     struct type_traits<boost::numeric::interval<double> > : scalar_traits<boost::numeric::interval<double> > {
00382         typedef type_traits<boost::numeric::interval<double> > self_type;
00383         typedef boost::numeric::interval<double> value_type;
00384         typedef const value_type &const_reference;
00385         typedef value_type &reference;
00386         typedef value_type real_type;
00387         typedef boost::numeric::interval<long double> precision_type;
00388     };
00389     template<>
00390     struct type_traits<boost::numeric::interval<long double> > : scalar_traits<boost::numeric::interval<long double> > {
00391         typedef type_traits<boost::numeric::interval<long double> > self_type;
00392         typedef boost::numeric::interval<long double> value_type;
00393         typedef const value_type &const_reference;
00394         typedef value_type &reference;
00395         typedef value_type real_type;
00396         typedef value_type precision_type;
00397     };
00398 #endif
00399 
00400 
00401     // Storage tags -- hierarchical definition of storage characteristics
00402 
00403     struct unknown_storage_tag {};
00404     struct sparse_proxy_tag: public unknown_storage_tag {};
00405     struct sparse_tag: public sparse_proxy_tag {};
00406     struct packed_proxy_tag: public sparse_proxy_tag {};
00407     struct packed_tag: public packed_proxy_tag {};
00408     struct dense_proxy_tag: public packed_proxy_tag {};
00409     struct dense_tag: public dense_proxy_tag {};
00410 
00411     template<class S1, class S2>
00412     struct storage_restrict_traits {
00413         typedef S1 storage_category;
00414     };
00415 
00416     template<>
00417     struct storage_restrict_traits<sparse_tag, dense_proxy_tag> {
00418         typedef sparse_proxy_tag storage_category;
00419     };
00420     template<>
00421     struct storage_restrict_traits<sparse_tag, packed_proxy_tag> {
00422         typedef sparse_proxy_tag storage_category;
00423     };
00424     template<>
00425     struct storage_restrict_traits<sparse_tag, sparse_proxy_tag> {
00426         typedef sparse_proxy_tag storage_category;
00427     };
00428 
00429     template<>
00430     struct storage_restrict_traits<packed_tag, dense_proxy_tag> {
00431         typedef packed_proxy_tag storage_category;
00432     };
00433     template<>
00434     struct storage_restrict_traits<packed_tag, packed_proxy_tag> {
00435         typedef packed_proxy_tag storage_category;
00436     };
00437     template<>
00438     struct storage_restrict_traits<packed_tag, sparse_proxy_tag> {
00439         typedef sparse_proxy_tag storage_category;
00440     };
00441 
00442     template<>
00443     struct storage_restrict_traits<packed_proxy_tag, sparse_proxy_tag> {
00444         typedef sparse_proxy_tag storage_category;
00445     };
00446 
00447     template<>
00448     struct storage_restrict_traits<dense_tag, dense_proxy_tag> {
00449         typedef dense_proxy_tag storage_category;
00450     };
00451     template<>
00452     struct storage_restrict_traits<dense_tag, packed_proxy_tag> {
00453         typedef packed_proxy_tag storage_category;
00454     };
00455     template<>
00456     struct storage_restrict_traits<dense_tag, sparse_proxy_tag> {
00457         typedef sparse_proxy_tag storage_category;
00458     };
00459 
00460     template<>
00461     struct storage_restrict_traits<dense_proxy_tag, packed_proxy_tag> {
00462         typedef packed_proxy_tag storage_category;
00463     };
00464     template<>
00465     struct storage_restrict_traits<dense_proxy_tag, sparse_proxy_tag> {
00466         typedef sparse_proxy_tag storage_category;
00467     };
00468 
00469 
00470     // Iterator tags -- hierarchical definition of storage characteristics
00471 
00472     struct sparse_bidirectional_iterator_tag : public std::bidirectional_iterator_tag {};
00473     struct packed_random_access_iterator_tag : public std::random_access_iterator_tag {};
00474     struct dense_random_access_iterator_tag : public packed_random_access_iterator_tag {};
00475 
00476     // Thanks to Kresimir Fresl for convincing Comeau with iterator_base_traits ;-)
00477     template<class IC>
00478     struct iterator_base_traits {};
00479 
00480     template<>
00481     struct iterator_base_traits<std::forward_iterator_tag> {
00482         template<class I, class T>
00483         struct iterator_base {
00484             typedef forward_iterator_base<std::forward_iterator_tag, I, T> type;
00485         };
00486     };
00487 
00488     template<>
00489     struct iterator_base_traits<std::bidirectional_iterator_tag> {
00490         template<class I, class T>
00491         struct iterator_base {
00492             typedef bidirectional_iterator_base<std::bidirectional_iterator_tag, I, T> type;
00493         };
00494     };
00495     template<>
00496     struct iterator_base_traits<sparse_bidirectional_iterator_tag> {
00497         template<class I, class T>
00498         struct iterator_base {
00499             typedef bidirectional_iterator_base<sparse_bidirectional_iterator_tag, I, T> type;
00500         };
00501     };
00502 
00503     template<>
00504     struct iterator_base_traits<std::random_access_iterator_tag> {
00505         template<class I, class T>
00506         struct iterator_base {
00507             typedef random_access_iterator_base<std::random_access_iterator_tag, I, T> type;
00508         };
00509     };
00510     template<>
00511     struct iterator_base_traits<packed_random_access_iterator_tag> {
00512         template<class I, class T>
00513         struct iterator_base {
00514             typedef random_access_iterator_base<packed_random_access_iterator_tag, I, T> type;
00515         };
00516     };
00517     template<>
00518     struct iterator_base_traits<dense_random_access_iterator_tag> {
00519         template<class I, class T>
00520         struct iterator_base {
00521             typedef random_access_iterator_base<dense_random_access_iterator_tag, I, T> type;
00522         };
00523     };
00524 
00525     template<class I1, class I2>
00526     struct iterator_restrict_traits {
00527         typedef I1 iterator_category;
00528     };
00529 
00530     template<>
00531     struct iterator_restrict_traits<packed_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
00532         typedef sparse_bidirectional_iterator_tag iterator_category;
00533     };
00534     template<>
00535     struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, packed_random_access_iterator_tag> {
00536         typedef sparse_bidirectional_iterator_tag iterator_category;
00537     };
00538 
00539     template<>
00540     struct iterator_restrict_traits<dense_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
00541         typedef sparse_bidirectional_iterator_tag iterator_category;
00542     };
00543     template<>
00544     struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, dense_random_access_iterator_tag> {
00545         typedef sparse_bidirectional_iterator_tag iterator_category;
00546     };
00547 
00548     template<>
00549     struct iterator_restrict_traits<dense_random_access_iterator_tag, packed_random_access_iterator_tag> {
00550         typedef packed_random_access_iterator_tag iterator_category;
00551     };
00552     template<>
00553     struct iterator_restrict_traits<packed_random_access_iterator_tag, dense_random_access_iterator_tag> {
00554         typedef packed_random_access_iterator_tag iterator_category;
00555     };
00556 
00557     template<class I>
00558     BOOST_UBLAS_INLINE
00559     void increment (I &it, const I &it_end, typename I::difference_type compare, packed_random_access_iterator_tag) {
00560         it += (std::min) (compare, it_end - it);
00561     }
00562     template<class I>
00563     BOOST_UBLAS_INLINE
00564     void increment (I &it, const I &/* it_end */, typename I::difference_type /* compare */, sparse_bidirectional_iterator_tag) {
00565         ++ it;
00566     }
00567     template<class I>
00568     BOOST_UBLAS_INLINE
00569     void increment (I &it, const I &it_end, typename I::difference_type compare) {
00570         increment (it, it_end, compare, typename I::iterator_category ());
00571     }
00572 
00573     template<class I>
00574     BOOST_UBLAS_INLINE
00575     void increment (I &it, const I &it_end) {
00576 #if BOOST_UBLAS_TYPE_CHECK
00577         I cit (it);
00578         while (cit != it_end) {
00579             BOOST_UBLAS_CHECK (*cit == typename I::value_type/*zero*/(), internal_logic ());
00580             ++ cit;
00581         }
00582 #endif
00583         it = it_end;
00584     }
00585 
00586     namespace detail {
00587 
00588         // specialisation which define whether a type has a trivial constructor
00589         // or not. This is used by array types.
00590         template<typename T>
00591         struct has_trivial_constructor : public boost::has_trivial_constructor<T> {};
00592 
00593         template<typename T>
00594         struct has_trivial_destructor : public boost::has_trivial_destructor<T> {};
00595 
00596         template<typename FLT>
00597         struct has_trivial_constructor<std::complex<FLT> > : public boost::true_type {};
00598         
00599         template<typename FLT>
00600         struct has_trivial_destructor<std::complex<FLT> > : public boost::true_type {};
00601 
00602     }
00603 
00604 
00608     template < class E >
00609     struct container_view_traits {
00611         typedef typename E::size_type             size_type;
00613         typedef typename E::difference_type       difference_type;
00614 
00616         typedef typename E::storage_category      storage_category;
00617 
00619         typedef typename E::value_type            value_type;
00621         typedef typename E::const_reference       const_reference;
00622   
00624         typedef typename E::const_closure_type    const_closure_type;
00625     };
00626 
00630     template < class E >
00631     struct mutable_container_traits {
00633         typedef typename E::reference             reference;
00634   
00636         typedef typename E::closure_type          closure_type;
00637     };
00638 
00642     template < class E >
00643     struct container_traits 
00644         : container_view_traits<E>, mutable_container_traits<E> {
00645 
00646     };
00647 
00648 
00652     template < class MATRIX >
00653     struct matrix_view_traits : container_view_traits <MATRIX> {
00654 
00656         typedef typename MATRIX::orientation_category  orientation_category;
00657   
00659         typedef typename MATRIX::const_iterator1  const_iterator1;
00660 
00662         typedef typename MATRIX::const_iterator2  const_iterator2;
00663     };
00664 
00668     template < class MATRIX >
00669     struct mutable_matrix_traits 
00670         : mutable_container_traits <MATRIX> {
00671 
00673         typedef typename MATRIX::iterator1  iterator1;
00674 
00676         typedef typename MATRIX::iterator2  iterator2;
00677     };
00678 
00679 
00683     template < class MATRIX >
00684     struct matrix_traits 
00685         : matrix_view_traits <MATRIX>, mutable_matrix_traits <MATRIX> {
00686     };
00687 
00691     template < class VECTOR >
00692     struct vector_view_traits : container_view_traits <VECTOR> {
00693 
00695         typedef typename VECTOR::const_iterator  const_iterator;
00696 
00698         static
00699         const_iterator begin(const VECTOR & v) {
00700             return v.begin();
00701         }
00703         static
00704         const_iterator end(const VECTOR & v) {
00705             return v.end();
00706         }
00707 
00708     };
00709 
00713     template < class VECTOR >
00714     struct mutable_vector_traits : mutable_container_traits <VECTOR> {
00716         typedef typename VECTOR::iterator  iterator;
00717 
00719         static
00720         iterator begin(VECTOR & v) {
00721             return v.begin();
00722         }
00723 
00725         static
00726         iterator end(VECTOR & v) {
00727             return v.end();
00728         }
00729     };
00730 
00734     template < class VECTOR >
00735     struct vector_traits 
00736         : vector_view_traits <VECTOR>, mutable_vector_traits <VECTOR> {
00737     };
00738 
00739 
00740     // Note: specializations for T[N] and T[M][N] have been moved to traits/c_array.hpp
00741 
00742 }}}
00743 
00744 #endif