Могу ли я специализировать std::begin и std::end для возвращаемого значения equal_range()?

Заголовок <algorithm> предоставляет std::equal_range(), а также некоторые контейнеры, имеющие его в качестве функции-члена. Что меня беспокоит в этой функции, так это то, что она возвращает пару итераторов, что делает утомительным итерацию от начального итератора к конечному итератору. Я хотел бы иметь возможность использовать std::begin() и std::end(), чтобы я мог использовать цикл for на основе диапазона С++ 11.

Теперь я слышал противоречивую информацию относительно специализации std::begin() и std::end() - мне сказали, что добавление чего-либо в пространство имен std приводит к неопределенному поведению, тогда как мне также сказали, что вы можете предоставить свои собственные специализации std::begin() и std::end() .

Вот что я делаю прямо сейчас:

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;
    }
}

И это работает: http://ideone.com/wHVfkh

Но мне интересно, какие минусы в этом? Есть лучший способ сделать это?


person LB--    schedule 11.10.2013    source источник


Ответы (1)


17.6.4.2.1/1 Поведение программы C++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен внутри пространства имен std, если не указано иное. Программа может добавить специализацию шаблона для любого шаблона стандартной библиотеки в пространство имен std только в том случае, если объявление зависит от определяемого пользователем типа и специализация соответствует требованиям стандартной библиотеки для исходного шаблона и не запрещена явно.

Так что да, я считаю, что технически ваш код демонстрирует неопределенное поведение. Возможно, вы можете написать простой класс, который принимает пару итераторов в своем конструкторе и реализует методы begin() и end(). Затем вы можете написать что-то вроде

for (const auto& elem: as_range(equal_range(...))) {}
person Igor Tandetnik    schedule 11.10.2013
comment
Насколько «привередливой» является часть о том, что это разрешено, если задействованы пользовательские типы? Пара содержит итераторы, которые выполняют итерацию по контейнеру unique_ptrs для моего пользовательского типа. - person LB--; 12.10.2013
comment
В написанных вами определениях не упоминаются какие-либо пользовательские типы. Эти шаблоны в конечном итоге могут быть созданы с помощью определяемых пользователем типов, но это не имеет значения. - person Igor Tandetnik; 12.10.2013
comment
В любом случае, выход из зависимости от определяемых пользователем типов применим только к специализациям шаблона. Ваши — нет: это основные шаблоны функций, которые просто перегружают другие шаблоны функций с тем же именем. - person Igor Tandetnik; 12.10.2013
comment
Просто добавим, что исключение специализации шаблона — это то, что позволяет нам специализировать std::hash. - person DanielKO; 12.10.2013