Hide the predicate type of a filter_iterator?
Hello everyone Imagine a class "numbers" that contains some values and methods like getEvenValues(), getOddValues(), getValuesLarger100() etc. Those methods return an iterator range of filter_iterators. In the the code I posted below, I'd have to define a different iterator_range of filter_iterator types for all the different methods (numbers::EvenFilterRange, numbers::OddFilterRange etc.). Is there some way to "hide" the type of the predicate used in a filter_iterator, so that it would be possible to have a generic "NumberRange" type for the return values of all methods? Something like: class numbers { typedef NumberRange ????; NumberRange getEvenValues() const; NumberRange getOddValues() const; NumberRange getValuesLarger100() const; } Thanks for your hints James /*********************************************/ #include <vector> #include <iostream> #include <boost/iterator/filter_iterator.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/range/iterator_range.hpp> using namespace std; using namespace boost; /*********************************************/ template<typename T> struct is_even { bool operator()(const T &t) { return t % 2 == 0; } }; template<typename T> struct is_odd { bool operator()(const T &t) { return t % 2 != 0; } }; /*********************************************/ class numbers { public: typedef vector<int> NumberContainer; typedef NumberContainer::const_iterator NumberIter; typedef iterator_range< filter_iterator< is_even<numbers::NumberContainer::value_type>, NumberIter> > EvenFilterRange; numbers() { copy( counting_iterator<NumberContainer::value_type>(0), counting_iterator<NumberContainer::value_type>(100), back_inserter(m_vec) ); } template<typename Pred> iterator_range<filter_iterator<Pred, NumberIter> > getValues(const Pred &pred) { return make_iterator_range( make_filter_iterator(pred, m_vec.begin(), m_vec.end()), make_filter_iterator(pred, m_vec.end(), m_vec.end()) ); } EvenFilterRange getEvenValues() { typedef is_even<numbers::NumberContainer::value_type> PredType; PredType is_even_predicate; return getValues(is_even_predicate); }; private: NumberContainer m_vec; }; /*********************************************/ template<typename T> struct print_number { void operator()(const T &t) { cout << "Number: " << t << endl; } }; /*********************************************/ int main() { numbers n; numbers::EvenFilterRange even_filter_range = n.getEvenValues(); print_number<numbers::NumberContainer::value_type> printer; for_each(begin(even_filter_range), end(even_filter_range), printer); }
AMDG Jean-Pierre Bergamin wrote:
Hello everyone
Imagine a class "numbers" that contains some values and methods like getEvenValues(), getOddValues(), getValuesLarger100() etc. Those methods return an iterator range of filter_iterators. In the the code I posted below, I'd have to define a different iterator_range of filter_iterator types for all the different methods (numbers::EvenFilterRange, numbers::OddFilterRange etc.). Is there some way to "hide" the type of the predicate used in a filter_iterator, so that it would be possible to have a generic "NumberRange" type for the return values of all methods? Something like:
class numbers { typedef NumberRange ????; NumberRange getEvenValues() const; NumberRange getOddValues() const; NumberRange getValuesLarger100() const; }
Try using boost::function<bool(int)> for the predicate type. In Christ, Steven Watanabe
Hello again Steven Watanabe wrote:
AMDG
Jean-Pierre Bergamin wrote:
Hello everyone
Imagine a class "numbers" that contains some values and methods like getEvenValues(), getOddValues(), getValuesLarger100() etc. Those methods return an iterator range of filter_iterators. In the the code I posted below, I'd have to define a different iterator_range of filter_iterator types for all the different methods (numbers::EvenFilterRange, numbers::OddFilterRange etc.). Is there some way to "hide" the type of the predicate used in a filter_iterator, so that it would be possible to have a generic "NumberRange" type for the return values of all methods? Something like:
class numbers { typedef NumberRange ????; NumberRange getEvenValues() const; NumberRange getOddValues() const; NumberRange getValuesLarger100() const; }
Try using boost::function<bool(int)> for the predicate type.
Thank you Steven. Using boost::function as the predicate type does the trick. For the sake of completeness, I post some code at the bottom. I think this is a very useful method to provide filtered values to a user, without copying any elements. Regards James /*********************************************/ #include <vector> #include <iostream> #include <boost/iterator/filter_iterator.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/range/iterator_range.hpp> #include <boost/function.hpp> #include <boost/bind.hpp> using namespace std; using namespace boost; /*********************************************/ template<typename T> struct is_even { bool operator()(const T &t) { return t % 2 == 0; } }; template<typename T> struct is_odd { bool operator()(const T &t) { return t % 2 != 0; } }; template<typename T> struct is_greater_then { is_greater_then(const T &t) :m_t(t) { } bool operator()(const T &t) { return t > m_t; } private: T m_t; }; /*********************************************/ template<typename T> class numbers { public: typedef T type; typedef vector<typename T> NumberContainer; typedef typename NumberContainer::const_iterator NumberIter; typedef boost::function<bool(T)> PredFunction; typedef iterator_range< filter_iterator< PredFunction, NumberIter> > NumberRange; numbers() { copy( counting_iterator<T>(0), counting_iterator<T>(100), back_inserter(m_numbers) ); } template<typename Pred> NumberRange getValues(const Pred &pred) { return make_iterator_range( make_filter_iterator(pred, m_numbers.begin(), m_numbers.end()), make_filter_iterator(pred, m_numbers.end(), m_numbers.end()) ); } NumberRange getEvenValues() { PredFunction pred = bind<bool>(is_even<T>(), _1); return getValues(pred); }; NumberRange getOddValues() { PredFunction pred = bind<bool>(is_odd<T>(), _1); return getValues(pred); }; private: NumberContainer m_numbers; }; /*********************************************/ template<typename T> struct print_number { void operator()(const T &t) { cout << "Number: " << t << endl; } }; /*********************************************/ int main() { typedef numbers<long> ints; print_number<ints::type> printer; ints my_ints; cout << "Even values" << endl; ints::NumberRange even_range = my_ints.getEvenValues(); for_each(begin(even_range), end(even_range), printer); cout << "Odd values" << endl; ints::NumberRange odd_range = my_ints.getOddValues(); for_each(begin(odd_range), end(odd_range), printer); cout << "> 50" << endl; ints::PredFunction pred = bind<bool>(is_greater_then<ints::type>(50), _1); ints::NumberRange greater_50_range = my_ints.getValues(pred); for_each(begin(greater_50_range), end(greater_50_range), printer); }
Jean-Pierre Bergamin schrieb:
Hello again
Steven Watanabe wrote:
Try using boost::function<bool(int)> for the predicate type.
Thank you Steven. Using boost::function as the predicate type does the trick. For the sake of completeness, I post some code at the bottom. I think this is a very useful method to provide filtered values to a user, without copying any elements.
Copying is of course only avoided if the Predicate function is defined as boost::function<bool(const T&)> PredFunction. James
participants (2)
-
Jean-Pierre Bergamin
-
Steven Watanabe