ivl 679
|
00001 /* This file is part of the ivl C++ library <http://image.ntua.gr/ivl>. 00002 A C++ template library extending syntax towards mathematical notation. 00003 00004 Copyright (C) 2012 Yannis Avrithis <iavr@image.ntua.gr> 00005 Copyright (C) 2012 Kimon Kontosis <kimonas@image.ntua.gr> 00006 00007 ivl is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU Lesser General Public License 00009 version 3 as published by the Free Software Foundation. 00010 00011 Alternatively, you can redistribute it and/or modify it under the terms 00012 of the GNU General Public License version 2 as published by the Free 00013 Software Foundation. 00014 00015 ivl is distributed in the hope that it will be useful, 00016 but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00018 See the GNU General Public License for more details. 00019 00020 You should have received a copy of the GNU General Public License 00021 and a copy of the GNU Lesser General Public License along 00022 with ivl. If not, see <http://www.gnu.org/licenses/>. */ 00023 00041 template <class T, 00042 class IT, 00043 class CONST_IT, 00044 int LENGTH, 00045 class HAS_C_PTR, 00046 class DERIVED_INFO 00047 > 00048 class array<T, data::ref_iterator<IT, CONST_IT, LENGTH, HAS_C_PTR, 00049 DERIVED_INFO> > 00050 : 00051 public array_common_base<array<T, 00052 data::ref_iterator<IT, CONST_IT, LENGTH, typename HAS_C_PTR::type, 00053 DERIVED_INFO> > >, 00054 00055 public data::referer<typename types::derive< 00056 array<T, data::ref_iterator<IT, CONST_IT, LENGTH, 00057 typename HAS_C_PTR::type, DERIVED_INFO> > >::type>, 00058 00059 public array_details::ref_iterator_extender< 00060 array<T, data::ref_iterator<IT, CONST_IT, LENGTH, 00061 typename HAS_C_PTR::type, 00062 DERIVED_INFO> >, T, IT, CONST_IT, typename HAS_C_PTR::type> 00063 { 00064 private: 00065 /*//compiler error checking section: this section generates compiler errors 00069 00070 // template code for error 00100 00071 typedef typename types::t_if<types::t_and<types::t_neq< 00072 typename types::derive<array>::type, array>, types::t_not< 00073 typename array::has_random_access> >, float, int>::type 00074 ivl_compile_error_00100_t; 00075 00076 // ----------------------------------------------------------------------------- 00077 00078 enum { 00079 // error: you are trying to define an array_nd of type ref_iterator 00080 // with a non-random access iterator type. 00081 ivl_compile_error_00100 = ivl_compile_error_00100_t(0) 00082 }; 00083 00084 /*//end of error checking section/// 00085 //*/ 00086 typedef array_common_base<array<T, data::ref_iterator<IT, 00087 CONST_IT, LENGTH, typename HAS_C_PTR::type, 00088 DERIVED_INFO> > > common_base_class; 00089 00090 typedef array_details::ref_iterator_extender< 00091 array<T, data::ref_iterator<IT, CONST_IT, LENGTH, 00092 typename HAS_C_PTR::type, 00093 DERIVED_INFO> >, 00094 T, IT, CONST_IT, typename HAS_C_PTR::type> ext_base; 00095 00096 template<class X, class Y, class Z> 00097 friend class array_details::ref_iterator_add_write_rnd_op; 00098 template<class X, class Y, class Z> 00099 friend class array_details::ref_iterator_add_const_rnd_op; 00100 template<class X, class Y> 00101 friend class array_details::ref_iterator_add_const_it; 00102 template<class X, class Y> 00103 friend class array_details::ref_iterator_add_write_it; 00104 // types 00105 00106 // struct used to disable some members 00107 struct not_a_type { template<class X> not_a_type(X){} }; 00108 struct invalid_arguments { template<class X> invalid_arguments(X){} }; 00109 00110 typedef typename ext_base::wr_best_it stored_it_type; 00111 typedef typename std::iterator_traits<stored_it_type> 00112 ::reference prv_reference; 00113 00114 // type control for fixed template length / any length 00115 00116 // struct that behaves like size_t and always returns N 00117 struct get_n 00118 { 00119 get_n() {} 00120 get_n(size_t l) { CHECK(l == LENGTH, ecomp); } 00121 operator size_t() { return LENGTH; } 00122 void operator= (size_t) {} 00123 }; 00124 00125 typedef typename types::t_if<types::t_expr<LENGTH == 0>, 00126 size_t, get_n>::type stored_len_type; 00127 00128 typedef typename types::t_if<types::t_expr<LENGTH == 0>, 00129 types::skip, invalid_arguments>::type illegal_if_fixedlen; 00130 00131 typedef typename types::t_if<types::t_expr<LENGTH != 0>, 00132 types::skip, invalid_arguments>::type illegal_ifn_fixedlen; 00133 00134 // type control for random access / no random access 00135 struct unused_iter 00136 { 00137 unused_iter() {} 00138 template<class X> 00139 unused_iter(X x) {} 00140 }; 00141 00142 typedef typename array::wr_has_random_access is_rnd; 00143 typedef typename array::is_writeable is_wrt; 00144 00145 typedef typename types::t_if<is_rnd, 00146 unused_iter, stored_it_type>::type end_iter_type; 00147 00148 typedef typename types::t_if<is_rnd, 00149 types::skip, invalid_arguments>::type illegal_ifn_rnd; 00150 00151 typedef typename types::t_if< 00152 types::t_and<is_rnd, types::t_expr<LENGTH == 0> >, 00153 types::skip, invalid_arguments>::type illegal_ifn_rnd_and_fixedlen; 00154 00155 typedef typename types::t_if<is_wrt, 00156 invalid_arguments, types::skip>::type illegal_if_writeable; 00157 // members 00158 00159 stored_it_type base_ptr; 00160 00161 stored_len_type len; 00162 00163 end_iter_type end_iter; 00164 00165 typename array_details::ref_iterator_memmanage<HAS_C_PTR>::store_type mmst; 00166 00167 // helper functions 00168 inline 00169 stored_it_type& get_it_end(stored_it_type& it_end) { return it_end; } 00170 00171 inline 00172 const stored_it_type& get_it_end(const stored_it_type& it_end) const 00173 { return it_end; } 00174 00175 inline 00176 stored_it_type get_it_end(const unused_iter&) 00177 { return base_ptr + size_t(len); } 00178 00179 inline 00180 stored_it_type get_it_end(const unused_iter&) const 00181 { return base_ptr + size_t(len); } 00182 00183 inline 00184 stored_it_type dec_iter(stored_it_type it) { return --it; } 00185 00186 struct invalid_data_init_arg 00187 { 00188 operator stored_it_type() { return stored_it_type(); } 00189 }; 00190 00191 struct ref_iterator_initializer 00192 { 00193 stored_it_type base_ptr; 00194 stored_len_type len; 00195 end_iter_type end_iter; 00196 00198 template<class J, class S> 00199 ref_iterator_initializer(const array<J, S>& a) 00200 : base_ptr( 00201 array_details::ref_iterator_from_array<const array<J, S>, 00202 typename types::is_ptr<stored_it_type>::type>::begin_raw(a)), 00203 //a.begin()), 00204 len(a.length()), 00205 end_iter( 00206 array_details::ref_iterator_from_array<const array<J, S>, 00207 typename types::is_ptr<stored_it_type>::type>::end_raw(a))/*, 00208 //a.end()), 00209 mmst(false) { }*/ 00210 { 00211 } 00212 00214 template<class J, class S> 00215 ref_iterator_initializer(array<J, S>& a) 00216 : base_ptr( 00217 array_details::ref_iterator_from_array<array<J, S>, 00218 typename types::is_ptr<stored_it_type>::type>::begin_raw(a)), 00219 //a.begin()), 00220 len(a.length()), 00221 end_iter( 00222 array_details::ref_iterator_from_array<array<J, S>, 00223 typename types::is_ptr<stored_it_type>::type>::end_raw(a))/*, 00224 //a.end()), 00225 mmst(false) { }*/ 00226 { 00227 } 00228 }; 00229 00230 public: 00231 00232 //overriden data class traits 00233 typedef typename ext_base::has_c_ptr has_c_ptr; 00234 00235 typedef array this_type; 00236 00237 typedef this_type this_array_type; 00238 00239 typedef this_type array_type; 00240 00241 typedef T elem_type; 00242 00243 typedef stored_it_type best_iterator; 00244 typedef typename std::iterator_traits<stored_it_type>::reference reference; 00245 typedef reference best_reference; 00246 typedef typename types::apply_const< 00247 typename std::iterator_traits<typename ext_base::wr_const_it> 00248 ::reference>::type const_reference; 00249 00250 typedef typename common_base_class::derived_type derived_type; 00251 00252 typedef typename common_base_class::base_class base_class; 00253 00256 00257 typedef typename types::t_if<types::t_and< 00258 types::is_ptr<stored_it_type>, is_wrt>, 00259 T*, invalid_data_init_arg>::type data_init_arg; 00260 00263 //typedef ref_iterator_initializer all_init_arg; 00264 00265 00267 typedef size_t size_type; 00268 00270 typedef ptrdiff_t diff_type; 00271 00272 using base_class::derived; 00273 00274 using common_base_class::operator[]; 00275 using ext_base::operator[]; 00276 00279 //TODO: explain this better. 00281 size_t length() const { return size_t(len); } 00283 size_type size() const { return length(); } 00285 size_t numel() const { return length(); } 00288 //todo: well 100% correct would be a 2-mode implementation 00289 //1 for random-access, 2 for non-ra, with stored begin and end inside. 00290 //but its more complicated. (cant override + with any iterator type) 00291 //so need to be able to get iter_border_walker type from iterator 00292 //type (like with i 00293 00294 typedef typename ext_base::iter_border_walker iter_border_walker; 00295 using ext_base::first_to_last; 00296 using ext_base::begin_to_end; 00297 00298 /* 00299 //#1 00300 typedef ptrdiff_t iter_border_walker; 00301 iter_border_walker first_to_last() const { return this->length() - 1; } 00302 iter_border_walker begin_to_end() const { return this->length(); } 00303 00304 //#2 00305 typedef typename (IT)::iter_border_walker iter_border_walker; 00306 iter_border_walker fist_to_last() const 00307 { 00308 stored_it_type end_1 = end(); 00309 --end_1; 00310 return iter_border_walker(begin(), end_1); 00311 } 00312 iter_border_walker begin_to_end() const 00313 { 00314 return iter_border_walker(begin(), end()); 00315 } 00316 */ 00317 00320 00321 array() : len(0) { } 00322 00324 explicit array(int) : len(0), base_ptr(stored_it_type()) { } 00325 00328 array(const stored_it_type& it, 00329 illegal_ifn_fixedlen disable = illegal_ifn_fixedlen(), 00330 illegal_ifn_rnd disable2 = illegal_ifn_rnd()) 00331 : base_ptr(it), end_iter(array::rnd_add(it, LENGTH)), mmst(false) { } 00332 00335 array(const stored_it_type& it, size_t n, 00336 illegal_if_fixedlen disable = illegal_if_fixedlen(), 00337 illegal_ifn_rnd disable_cond_2 = illegal_ifn_rnd()) 00338 : base_ptr(it), len(n), end_iter(array::rnd_add(it, n)), mmst(false) { } 00339 00342 array(const stored_it_type& it, size_t n, const stored_it_type& it_end, 00343 illegal_if_fixedlen disable = illegal_if_fixedlen()) 00344 : base_ptr(it), len(n), end_iter(it_end), mmst(false) { } 00345 00348 array(const stored_it_type& it, const stored_it_type& it_end, size_t n) 00349 : base_ptr(it), len(n), end_iter(it_end), mmst(false) { } 00350 00353 array(const stored_it_type& it, const stored_it_type& it_end, 00354 illegal_ifn_rnd_and_fixedlen disable = illegal_ifn_rnd_and_fixedlen()) 00355 : base_ptr(it), len(array::rnd_sub(it_end, it)), 00356 end_iter(it_end), mmst(false) { } 00357 00359 array(const this_type& a) 00360 : base_ptr(a.base_ptr), len(a.len), 00361 end_iter(a.end_iter), mmst(false) { } 00362 00363 // -- array based constructors -- 00364 00366 template <class J, class S> 00367 array(size_t len, const array<J, S>& a) 00368 : base_ptr( 00369 array_details::ref_iterator_from_array<const array<J, S>, 00370 typename types::is_ptr<stored_it_type>::type>::begin_raw(a)), 00371 //a.begin()), 00372 len(len), 00373 end_iter(array::rnd_add( 00374 00375 array_details::ref_iterator_from_array<const array<J, S>, 00376 typename types::is_ptr<stored_it_type>::type>::begin_raw(a), 00377 //a.begin(), 00378 00379 len)), mmst(false) { } 00380 00382 template <class J, class S> 00383 array(size_t len, array<J, S>& a) 00384 : base_ptr( 00385 array_details::ref_iterator_from_array<array<J, S>, 00386 typename types::is_ptr<stored_it_type>::type>::begin_raw(a)), 00387 //a.begin()), 00388 len(len), 00389 end_iter(array::rnd_add( 00390 array_details::ref_iterator_from_array<array<J, S>, 00391 typename types::is_ptr<stored_it_type>::type>::begin_raw(a), 00392 //a.begin(), 00393 len)), mmst(false) { } 00394 00395 // -- 00396 /* 00398 array(const all_init_arg& z) 00399 : base_ptr(z.base_ptr), len(z.len), end_iter(z.end_iter), mmst(false) 00400 { 00401 } 00402 */ 00404 template<class J, class S> 00405 array(const array<J, S>& a) 00406 : base_ptr( 00407 array_details::ref_iterator_from_array<const array<J, S>, 00408 typename types::is_ptr<stored_it_type>::type>::begin_raw(a)), 00409 //a.begin()), 00410 len(a.length()), 00411 end_iter( 00412 array_details::ref_iterator_from_array<const array<J, S>, 00413 typename types::is_ptr<stored_it_type>::type>::end_raw(a)), 00414 //a.end()), 00415 mmst(false) { } 00416 00418 template<class J, class S> 00419 array(array<J, S>& a) 00420 : base_ptr( 00421 array_details::ref_iterator_from_array<array<J, S>, 00422 typename types::is_ptr<stored_it_type>::type>::begin_raw(a)), 00423 //a.begin()), 00424 len(a.length()), 00425 end_iter( 00426 array_details::ref_iterator_from_array<array<J, S>, 00427 typename types::is_ptr<stored_it_type>::type>::end_raw(a)), 00428 //a.end()), 00429 mmst(false) { } 00430 00431 00436 00437 array(size_t) : base_ptr(stored_it_type()) {} 00438 00440 array(size_t len, const T* ptr, illegal_if_writeable = illegal_if_writeable()) 00441 : base_ptr(types::r_if<types::t_eq<stored_it_type, const T*> > 00442 (ptr, stored_it_type())), len(len), mmst(false) 00443 { 00444 end_iter = array::rnd_add(base_ptr, len); 00445 } 00447 array(size_t len, const data_init_arg& y) 00448 : base_ptr(y), len(len), mmst(false) 00449 { 00450 end_iter = array::rnd_add(base_ptr, len); 00451 mmst = false; 00452 } 00453 00454 /* 00455 array(size_t len, T* ptr) 00456 : base_ptr(types::r_if<types::t_eq<stored_it_type, T*> > 00457 (ptr, stored_it_type())), len(len), mmst(false) 00458 { 00459 std::cout << "Chain constructor nc: " << (size_t)ptr << std::endl; 00460 end_iter = array::rnd_add(base_ptr, len); 00461 } 00462 */ 00463 00470 void set_null() 00471 { 00472 base_ptr = stored_it_type(); 00473 } 00474 bool is_null() const 00475 { 00476 return base_ptr == stored_it_type(); 00477 } 00478 void set_free(bool enable = true) 00479 { 00480 mmst = enable; 00481 } 00482 00485 //---------------------------------------------------- 00489 //setup functions are same as the constructors for provided iterators 00490 void init(const array& o) 00491 { 00492 base_ptr = o.base_ptr; 00493 len = o.len; 00494 end_iter = o.end_iter; 00495 mmst = false; 00496 } 00497 00498 void init(const stored_it_type& it, 00499 illegal_ifn_fixedlen disable = illegal_ifn_fixedlen(), 00500 illegal_ifn_rnd disable2 = illegal_ifn_rnd()) 00501 { 00502 base_ptr = it; 00503 end_iter = array::rnd_add(it, LENGTH); 00504 mmst = false; 00505 } 00506 00507 void init(const stored_it_type& it, size_t n, 00508 illegal_if_fixedlen disable = illegal_if_fixedlen(), 00509 illegal_ifn_rnd disable_cond_2 = illegal_ifn_rnd()) 00510 { 00511 base_ptr = it; 00512 len = n; 00513 end_iter = array::rnd_add(it, n); 00514 mmst = false; 00515 } 00516 00517 void init(const stored_it_type& it, size_t n, const stored_it_type& it_end, 00518 illegal_if_fixedlen disable = illegal_if_fixedlen()) 00519 { 00520 base_ptr = it; 00521 len = n; 00522 end_iter = it_end; 00523 mmst = false; 00524 } 00525 00526 void init(const stored_it_type& it, const stored_it_type& it_end, size_t n) 00527 { 00528 base_ptr = it; 00529 len = n; 00530 end_iter = it_end; 00531 mmst = false; 00532 } 00533 00534 void init(const stored_it_type& it, const stored_it_type& it_end, 00535 illegal_ifn_rnd_and_fixedlen disable = illegal_ifn_rnd_and_fixedlen()) 00536 { 00537 base_ptr = it; 00538 len = array::rnd_sub(it_end, it); 00539 end_iter = it_end; 00540 mmst = false; 00541 } 00542 00543 // -- array based constructors -- 00544 00546 template <class J, class S> 00547 void init(size_t len, const array<J, S>& a) 00548 { 00549 base_ptr = 00550 array_details::ref_iterator_from_array<const array<J, S>, 00551 typename types::is_ptr<stored_it_type>::type>::begin_raw(a); 00552 //a.begin()), 00553 this->len = len; 00554 end_iter = array::rnd_add( 00555 00556 array_details::ref_iterator_from_array<const array<J, S>, 00557 typename types::is_ptr<stored_it_type>::type>::begin_raw(a), 00558 //a.begin(), 00559 00560 len); 00561 mmst = false; 00562 } 00563 00565 template <class J, class S> 00566 void init(size_t len, array<J, S>& a) 00567 { 00568 base_ptr = 00569 array_details::ref_iterator_from_array<array<J, S>, 00570 typename types::is_ptr<stored_it_type>::type>::begin_raw(a); 00571 //a.begin()), 00572 this->len = len; 00573 end_iter = array::rnd_add( 00574 array_details::ref_iterator_from_array<array<J, S>, 00575 typename types::is_ptr<stored_it_type>::type>::begin_raw(a), 00576 //a.begin(), 00577 len); 00578 mmst = false; 00579 } 00580 /* 00582 void init(const all_init_arg& z) 00583 { 00584 base_ptr = z.base_ptr; 00585 len = z.len; 00586 end_iter = z.end_iter; 00587 mmst = false; 00588 } 00589 // -- 00590 */ 00592 template<class J, class S> 00593 void init(const array<J, S>& a) 00594 { 00595 base_ptr = 00596 array_details::ref_iterator_from_array<const array<J, S>, 00597 typename types::is_ptr<stored_it_type>::type>::begin_raw(a); 00598 //a.begin()), 00599 len = a.length(); 00600 end_iter = 00601 array_details::ref_iterator_from_array<const array<J, S>, 00602 typename types::is_ptr<stored_it_type>::type>::end_raw(a); 00603 //a.end()), 00604 mmst = false; 00605 } 00606 00608 template<class J, class S> 00609 void init(array<J, S>& a) 00610 { 00611 base_ptr = 00612 array_details::ref_iterator_from_array<array<J, S>, 00613 typename types::is_ptr<stored_it_type>::type>::begin_raw(a); 00614 //a.begin()), 00615 len = a.length(); 00616 end_iter = 00617 array_details::ref_iterator_from_array<array<J, S>, 00618 typename types::is_ptr<stored_it_type>::type>::end_raw(a); 00619 //a.end()), 00620 mmst = false; 00621 } 00622 00623 00624 void init(size_t s) // for NULL! 00625 { 00626 if(s == 0) 00627 base_ptr = stored_it_type(); 00628 } 00629 00631 void init(size_t len, const T* ptr, 00632 illegal_if_writeable disable = illegal_if_writeable()) 00633 { 00634 base_ptr = types::r_if<types::t_eq<stored_it_type, const T*> > 00635 (ptr, stored_it_type()); 00636 this->len = len; 00637 end_iter = array::rnd_add(base_ptr, len); 00638 mmst = false; 00639 } 00640 /* 00642 void init(size_t len, T* ptr) 00643 { 00644 base_ptr = types::r_if<types::t_eq<stored_it_type, T*> > 00645 (ptr, stored_it_type()); 00646 this->len = len; 00647 end_iter = array::rnd_add(base_ptr, len); 00648 mmst = false; 00649 } 00650 */ 00651 void init(size_t len, const data_init_arg& y) 00652 { 00653 base_ptr = y; 00654 this->len = len; 00655 end_iter = array::rnd_add(base_ptr, len); 00656 mmst = false; 00657 } 00658 00663 //setup functions are same as the constructors for provided iterators 00664 void setref(const array& o) { init(o); } 00665 00666 void setref(const stored_it_type& it, 00667 illegal_ifn_fixedlen disable = illegal_ifn_fixedlen(), 00668 illegal_ifn_rnd disable2 = illegal_ifn_rnd()) { init(it); } 00669 00670 void setref(const stored_it_type& it, size_t n, 00671 illegal_if_fixedlen disable = illegal_if_fixedlen(), 00672 illegal_ifn_rnd disable_cond_2 = illegal_ifn_rnd()) { init(it, n); } 00673 00674 void setref(const stored_it_type& it, size_t n, const stored_it_type& it_end, 00675 illegal_if_fixedlen disable = illegal_if_fixedlen()) 00676 { init(it, n, it_end); } 00677 00678 void setref(const stored_it_type& it, const stored_it_type& it_end, size_t n) 00679 { init(it, it_end, n); } 00680 00681 void setref(const stored_it_type& it, const stored_it_type& it_end, 00682 illegal_ifn_rnd_and_fixedlen disable = illegal_ifn_rnd_and_fixedlen()) 00683 { init(it, it_end); } 00684 00685 // -- array based setref -- 00686 template <class J, class S> 00687 void setref(size_t len, const array<J, S>& a) { init(len, a); } 00688 00689 template <class J, class S> 00690 void setref(size_t len, array<J, S>& a) { init(len, a); } 00691 00692 template<class J, class S> 00693 void setref(const array<J, S>& a) { init(a); } 00694 00695 template<class J, class S> 00696 void setref(array<J, S>& a) { init(a); } 00697 00698 // void setref(const all_init_arg& a) { init(a); } 00699 00700 void setref(size_t s) { init(s); } 00701 00702 void setref(size_t len, const T* ptr, 00703 illegal_if_writeable disable = illegal_if_writeable()) 00704 { init(len, ptr); } 00705 00706 void setref(size_t len, const data_init_arg& y) { init(len, y); } 00707 00710 00711 ~array() 00712 { 00713 // frees the memory on the special case of a data::deletable_c_ptr 00714 // and flag mmst == true. 00715 array_details::ref_iterator_memmanage<HAS_C_PTR>:: 00716 destroy(mmst, base_ptr); 00717 } 00718 00719 00723 //using common_base_class::operator=; 00724 template<class K> 00725 derived_type& operator=(const K& k) 00726 { 00727 common_base_class::operator=(k); 00728 return derived(); 00729 } 00730 00731 this_type& operator=(const this_type& a) 00732 { 00733 common_base_class::operator=(a); 00734 return *this; 00735 } 00737 using ext_base::overlap_array; 00738 using ext_base::overlap_element; 00739 00740 // TODO: needs different implementation. 00741 template <class D> 00742 bool self_overlap(const D& d) const { return overlap_array(d); } 00743 00744 /* 00745 template <class A> 00746 bool overlap(const A& a) const 00747 { 00748 return ext_base::overlap(a); 00749 //should check the pointers if you have pointers. 00750 //should have a few specializations concerning all the normal array 00751 //iterators, and iterator_nd objects and convert the to pointers and 00752 //then check them against the range (begin, end) of the other array 00753 //pointerwise. Although this ruins the beauty of the abstraction, 00754 //it does give us a really great way to predict and correct data 00755 //overlapping errors which could allow great results like safely using: 00756 //pixel = function(image area) 00757 // 00758 //for the current moment this is too much. 00759 //however, another good idea that saves the abstraction disaster 00760 //is to put a fourth optional bool template argument in the data class 00761 //which will tell us that &(*iter) is a pointer, and even though this 00762 //would be false by default, we could also enforce it by a hidden tag 00763 //in the participating iterators which will give us the same info. 00764 //with a logical or we can decide which is the case. 00765 return false; 00766 } 00767 */ 00768 00769 }; 00770