Let's say I want to write the following function,
void f(const list<int> &l, const vector<int> &v) {
cout << get_second(l) << '\n';
cout << get_second(v) << '\n';
cout << get_nth(l, 2) << '\n';
cout << get_nth(v, 2) << '\n';
}
that prints the second and third (counting from zero) items of given
list and vector.
For such a purpose I need to write the generic functions (i.e. function
templates) 'get_second' and'get_nth' that, respectively, return the
second and the n-th item of the given collection. Possible
implementations of these two functions are the following ones:
template<typename Coll>
inline typename Coll::value_type get_second(const Coll &coll) {
// return *++(coll.begin()); // Wrong.
// return *(coll.begin() + 1); // Wrong.
typename Coll::const_iterator it = coll.begin();
advance(it, 1);
return *it;
}
template<typename Coll, typename Distance>
inline typename Coll::value_type get_nth(
const Coll &coll, Distance d) {
typename Coll::const_iterator it = coll.begin();
advance(it, d);
return *it;
}
As noted in the code comments, the use of the operator '++' is wrong
(although some compilers accept it) as the function 'begin' shouldn't
return an l-value; and the use of the operator'+' is wrong for
non-random iterators, like those of list. So, the quickest solution I
found was that rather cumbersome code.
But I think that a better solution would be to define the following
function templates:
// Return the successor of the given input iterator.
template<typename InputIterator>
inline InputIterator succ(InputIterator it) {
return ++it;
}
// Return the predecessor of the given bidirectional iterator.
template<typename BidirectionalIterator>
inline BidirectionalIterator pred(BidirectionalIterator it) {
return --it;
}
// Return an input iterator moved from the given input iterator
// by the given distance.
template<typename InputIterator, typename Distance>
inline InputIterator adv(InputIterator it, Distance d) {
advance(it, d);
return it;
}
and then use them in the following function templates:
template<typename Coll>
inline typename Coll::value_type get_second(const Coll &coll) {
return *succ(coll.begin());
}
template<typename Coll, typename Distance>
inline typename Coll::value_type get_nth(const Coll &coll,
Distance d) {
return *adv(coll.begin(), d);
}
Is it a good idea to keep the functions 'succ', 'prec' and 'adv' in my
toolkit of generic utility functions, or are there better solutions?
--
Carlo Milanesi
http://digilander.libero.it/carlmila