The <algorithm> header provides std::equal_range(), as well as some containers having it as a member function. What bothers me with this function is that it returns a pair of iterators, making it tedious to iterate from the begin iterator to the end iterator. I'd like to be able to use std::begin() and std::end() so that I can use the C++11 range-based for-loop.
Now, I've heard contradictory information in regards to specializing std::begin() and std::end() - I've been told that adding anything to the std namespace results in undefined behavior, whereas I have also been told that you can provide your own specializations of std::begin() and std::end().
This is what I am doing right now:
namespace std
{
template<typename Iter, typename = typename iterator_traits<Iter>::iterator_category>
Iter begin(pair<Iter, Iter> const &p)
{
return p.first;
}
template<typename Iter, typename = typename iterator_traits<Iter>::iterator_category>
Iter end(pair<Iter, Iter> const &p)
{
return p.second;
}
}
And this does work: http://ideone.com/wHVfkh
But I am wondering, what are the downsides to doing this? Is there a better way to do this?
17.6.4.2.1/1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace
stdor to a namespace within namespacestdunless otherwise specified. A program may add a template specialization for any standard library template to namespacestdonly if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
So yes, I believe that, technically, your code exhibits undefined behavior. Perhaps you can write a simple class that takes a pair of iterators in its constructor and implements begin() and end() methods. Then you can write something like
for (const auto& elem: as_range(equal_range(...))) {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With