0

Почему доступ по диапазону для std::pair был удалён в C++11?

26

Я только что обнаружил, что в одном из черновиков C++11 были перегрузки stdbegin и stdend для std::pair, которые позволяли рассматривать пару итераторов как диапазон, подходящий для использования в цикле на основе диапазонов (N3126, раздел 20.3.5.5), но это было удалено.

Кто-нибудь знает, почему это было убрано?

Я считаю это удаление очень неудачным, потому что, похоже, нет другого способа рассматривать пару итераторов как диапазон. Действительно:

  • Правила поиска begin/end в цикле на основе диапазонов говорят о том, что begin/end ищутся в 1) как методы объекта диапазона 2) как свободные функции в "ассоциированных пространствах имен"
  • std::pair не имеет методов begin/end
  • Единственное ассоциированное пространство имен для std::pair<T, U> в общем случае - это пространство имен std
  • Нам нельзя перегружать std::begin/std::end для std::pair самостоятельно
  • Мы не можем специализированно определить std::begin/std::end для std::pair (поскольку специализация должна быть частичной, а это не допускается для функций)

Есть ли какой-то другой способ, о котором я не знаю?

2 ответ(ов)

0

Вы можете использовать boost::make_iterator_range. Этот метод создает iterator_range, который имеет методы begin() и end(). boost::make_iterator_range может принимать std::pair итераторов в качестве аргумента.

0

В вашем коде реализована обертка над парой итераторов с использованием C11, что упрощает работу с ними и позволяет использовать более удобный интерфейс. Давайте подробнее рассмотрим, как именно вы можете использовать оптимизации C11 и в чем преимущества такого подхода.

Объяснение кода

  1. Структура range_t: Это структура, наследующая от std::pair. Она содержит два итератора и предоставляет методы begin() и end(), что позволяет использовать экземпляры range_t в диапазонных циклах (range-based for loops).

    struct range_t : public std::pair<Iter, Iter> {
        using pair_t = std::pair<Iter, Iter>;
    
        range_t(pair_t&& src)
        : std::pair<Iter, Iter>(std::forward<pair_t>(src)) {}
    
        using std::pair<Iter, Iter>::first;
        using std::pair<Iter, Iter>::second;
    
        Iter begin() const { return first; }
        Iter end() const { return second; }
    };
    

    Здесь используется std::forward для идеальной передачи аргументов и обеспечения эффективного перемещения.

  2. Функция range: Вы определили две функции range, которые упрощают создание объектов range_t. Первая функция принимает пару итераторов, а вторая – два отдельных итератора. Обратите внимание на использование std::make_pair для создания пары.

    template<class Iter>
    range_t<Iter> range(std::pair<Iter, Iter> p) {
        return range_t<Iter>(std::move(p));
    }
    
    template<class Iter>
    range_t<Iter> range(Iter i1, Iter i2) {
        return range_t<Iter>(std::make_pair(std::move(i1), std::move(i2)));
    }
    

    Использование std::move здесь позволяет избежать лишнего копирования итераторов.

  3. Пример использования: В основной функции вы используете std::multiset, и благодаря вашей реализации можно элегантно выделить элементы, которые находятся в заданном диапазоне:

    multiset<int> mySet { 6,4,5,5,5,3,3,67,8,89,7,5,45,4,3 };
    
    for (const auto&i : range(mySet.lower_bound(5), mySet.upper_bound(10))) {
        cout << i << ",";
    }
    

    Этот код будет выводить все элементы, которые находятся между 5 и 10, включая 5.

  4. Подсчет и сумма: Также вы можете подсчитать количество вхождений определенного элемента и их сумму:

    for (const auto& i: range(mySet.equal_range(5))) {
        ++count;
        sum += i;
    }
    

    Пример показывает, как легко вы можете использовать ваш класс range_t в сочетании с функцией equal_range.

Заключение

Ваша реализация range_t является отличным примером использования C++11 для создания более удобного и безопасного кода с использованием семантики перемещения и того, как можно работать с диапазонами. Такой подход повышает читаемость кода и упрощает его использование, особенно когда это касается работы с итераторами и контейнерами.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь