You can encapsulate erasure to provide the same interface for all containers you use:
namespace detail { template<typename Container, typename R> struct SelectErase { // by default, assume the next iterator is returned template<typename Iterator> Iterator erase(Container& c, Iterator where) { return c.erase(where); } }; // specialize on return type void template<typename Container> struct SelectErase<Container, void> { template<typename Iterator> Iterator erase(Container& c, Iterator where) { Iterator next (where); ++next; c.erase(where); return next; } }; template<typename I, typename Container, typename R> SelectErase<Container,R> select_erase(R (Container::*)(I)) { return SelectErase<Container,R>(); } } // namespace detail template<typename Container, typename Iterator> Iterator erase(Container& container, Iterator where) { return detail::select_erase<Iterator>(&Container::erase).erase(container, where); }
This requires either:
- c.erase returns an iterator for the next element. Here's how the vector, deque, and list work.
- c.erase returns void and does not invalidate the next iterator. This is how map, set and (non-stdlib) hash_map work.
Roger Pate
source share