...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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