自动解包一对迭代器

Utk*_*pta 6 c++ argument-unpacking c++17

在 C++ 中,如果函数返回 a std::pair<int, int>,我们可以按如下方式自动接收它:

auto pr = some_function();
std::cout << pr.first << ' ' << pr.second;
Run Code Online (Sandbox Code Playgroud)

现在,C++17 标准提供了一种将这对直接解包为单独变量的漂亮方法,如下所示:

auto [x, y] = some_function();
std::cout << x << ' ' << y;
Run Code Online (Sandbox Code Playgroud)

然后是std::minmax_element()库函数,它返回一对迭代器。所以如果我将 a 传递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(*)
Run Code Online (Sandbox Code Playgroud)

现在我的问题是:有没有办法在解包时取消引用它们?或者更准确地说,给定以下代码,我可以用有效的 C++替换var1var2并打印这些迭代器指向的值吗?

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(*)
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 9

当然。编写一个函数,它接受一对可解引用的事物并返回解引用它们的结果:

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};
}
Run Code Online (Sandbox Code Playgroud)

然后使用该功能:

auto [var1, var2] = deref(std::minmax_element(v.begin(), v.end()));
Run Code Online (Sandbox Code Playgroud)

请注意,如果范围为空,则这是 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{};
Run Code Online (Sandbox Code Playgroud)

这使得:

auto [var1, var2] = std::minmax_element(v.begin(), v.end()) | deref;
Run Code Online (Sandbox Code Playgroud)

  • @cdhowie 这会做一些不同的事情 - 例如,如果 `v` 是一个 `vector&lt;int&gt;`,您的实现会给出一个 `pair&lt;int, int&gt;`,而我的实现会故意给出一个 `pair&lt;int&amp;, int&amp;&gt;`。 (3认同)