Автоматическая распаковка пары итераторов - PullRequest
5 голосов
/ 07 мая 2020

В C ++, если функция возвращает std::pair<int, int>, мы можем автоматически получить его следующим образом:

auto pr = some_function();
std::cout << pr.first << ' ' << pr.second;

Теперь стандарт C ++ 17 предоставляет прекрасный способ распаковки этой пары непосредственно в разделите переменные следующим образом:

auto [x, y] = some_function();
std::cout << x << ' ' << y;

И еще есть std::minmax_element() библиотечная функция, которая возвращает пару итераторов . Поэтому, если я передаю vector<int> этой функции, она вернет мне пару итераторов, указывающих на наименьший и наибольший элемент вектора.

Теперь я могу принять эти итераторы, как обычно, и затем отмените ссылки на них позже, как показано ниже.

std::vector<int> v = {4,1,3,2,5};
auto [x, y] = std::minmax_element(v.begin(), v.end());
std::cout << (*x) << ' ' << (*y);   // notice the asterisk(*)

Теперь мой вопрос: Есть ли способ удалить их во время распаковки? Или, точнее, с учетом следующего кода, Могу ли я заменить var1 и var2 на что-то, что является действительным C ++ и печатает значение, указанное этими итераторами?

std::vector<int> v = {4,1,3,2,5};
auto [var1, var2] = std::minmax_element(v.begin(), v.end());
std::cout << var1 << ' ' << var2;   // notice there is NO asterisk(*)

1 Ответ

8 голосов
/ 07 мая 2020

Конечно. Напишите функцию, которая принимает пару разыменованных вещей и возвращает результат разыменования:

template <typename Iterator,
    typename R = typename std::iterator_traits<Iterator>::reference>
auto deref(std::pair<Iterator, Iterator> p)
    -> std::pair<R, R>
{
    return {*p.first, *p.second};
}

А затем используйте эту функцию:

auto [var1, var2] = deref(std::minmax_element(v.begin(), v.end()));

Обратите внимание, что это UB, если диапазон пусто, потому что вы дважды разыменовываете конечный итератор.

Или, чтобы быть лучше:

struct deref_t {
    template <typename It,
        typename R = typename std::iterator_traits<Iterator>::reference>
    friend auto operator|(std::pair<It, It> p, deref_t)
        -> std::pair<R, R>
    {
        return { *p.first, *p.second };
    }
};
inline constexpr deref_t deref{};

Что позволяет:

auto [var1, var2] = std::minmax_element(v.begin(), v.end()) | deref;
...