If it got really bad, I would probably create a bunch of templates for my most commonly used algorithms in a new namespace:
namespace my_ranged_algorithms {
// Metafunction for extracting an appropriate iterator from
// the container type
template <typename T>
struct get_iterator_type_for;
// For vectors
template <typename T>
struct get_iterator_type_for<std::vector<T> > {
typedef typename std::vector<T>::iterator type;
};
template <typename T>
struct get_iterator_type_for<std::vector<T> const> {
typedef typename std::vector<T>::const_iterator type;
};
// For C arrays
template <typename T, size_t N>
struct get_iterator_type_for<T(&)[N]> {
typedef T* type;
};
// Generic begin() and end() wrappers
// For all standard containers
template <typename Cont>
typename get_iterator_type_for<Cont>::type begin(Cont& c) {
return c.begin();
}
template <typename Cont>
typename get_iterator_type_for<Cont>::type end(Cont& c) {
return c.end();
}
// For C arrays
template <typename T, size_t N>
typename get_iterator_type_for<T (&)[N]>::type begin(T (&c)[N]) {
return c;
}
template <typename T, size_t N>
typename get_iterator_type_for<T (&)[N]>::type end(T (&c)[N]) {
return c + N;
}
// Finally, the actual algorithm wrappers
// copy
template <typename Cont, typename OutIter>
OutIter copy(Cont& from, OutIter to) {
return std::copy(begin(from), end(from), to);
}
// remove
template <typename Cont, typename T>
typename get_iterator_type_for<Cont>::type remove(Cont& from, T x) {
return std::remove(begin(from), end(from), x);
}
// etc.
};
Then call them like so:
vector<int> a, b;
using namespace my_ranged_algorithms;
copy(a, back_inserter(b));
b.erase(remove(b, 42), b.end()); // Remember to call erase() after remove()!