有没有办法轻松处理函数返回std :: pairs?

C ++ 11有函数std::minmax_element ,它返回一对值。 然而,这样处理和阅读是相当混乱的,并且产生了一个额外的,后来无用的variables来污染范围。

 auto lhsMinmax = std::minmax_element(lhs.begin(), lhs.end()); int &lhsMin = *(lhsMinMax.first); int &lhsMax = *(lhsMinmax.second); 

有一个更好的方法吗? 就像是:

 int lhsMin; int lhsMax; std::make_pair<int&, int&>(lhsMin, lhsMax).swap( std::minmax_element(lhs.begin(), lhs.end())); 

这看起来像一个普通的情况下提示辅助function:

 template <class T, std::size_t...Idx> auto deref_impl(T &&tuple, std::index_sequence<Idx...>) { return std::tuple<decltype(*std::get<Idx>(std::forward<T>(tuple)))...>(*std::get<Idx>(std::forward<T>(tuple))...); } template <class T> auto deref(T &&tuple) -> decltype(deref_impl(std::forward<T>(tuple), std::make_index_sequence<std::tuple_size<std::remove_reference_t<T>>::value>{})) { return deref_impl(std::forward<T>(tuple), std::make_index_sequence<std::tuple_size<std::remove_reference_t<T>>::value>{}); } // ... int lhsMin; int lhsMax; std::tie(lhsMin,lhsMax) = deref(std::minmax_element(lhs.begin(), lhs.end())); 

index_sequence是C ++ 14,但可以在C ++ 11中完整实现。

注意:即使在C ++ 14中,我也会保留deref的返回types中的重复的decltype ,以便SFINAE可以应用。

在Coliru上看到它

使用C ++ 1z的结构化绑定 ,你可以直接做

 auto [lhsMinIt, lhsMaxIt] = std::minmax_element(lhs.begin(), lhs.end()); 

为了避免污染你的范围,你可以把这个任务放在一个较小的范围内:

 int lhsMin, lhsMax; { auto it = std::minmax_element(lhs.begin(), lhs.end()); lhsMin = *it.first; lhsMax = *it.second; } 

或者,您可以使用lambda

 int lhsMin, lhsMax; std::tie(lhsMin, lhsMax) = [&]{ auto it = std::minmax_element(lhs.begin(), lhs.end()); return std::make_tuple(*it.first, *it.second); }(); 

我只是更直接,写我自己的版本minmax_element

 template <class Iter, class R = typename iterator_traits<Iter>::reference> std::pair<R,R> deref_minmax(Iter first, Iter last) { auto iters = std::minmax_element(first, last); return std::pair<R,R>{*iters.first, *iters.second}; } 

那就是:

 int lo, hi; std::tie(lo, hi) = deref_minmax(lhs.begin(), lhs.end()); 

这将限制你只是一个单一的元素副本(这不是一个大的事情与int s),也让你保持访问到实际的容器的引用。


在C ++ 17中,为了好玩,我们可以写一个广义的解除引用:

 template <class Tuple> auto deref(Tuple&& tup) { return std::apply([](auto... args) { return std::tuple <decltype(*args)...>(*args...); }, tup); } auto& [lo, hi] = deref(std::minmax_element(lhs.begin(), lhs.end())); 

这里lohi是对容器本身的引用。

在标准的当前版本中,一次不能分配两个引用 ,如果这就是你所追求的。 请注意,除了需要C ++ 17和辅助模板的Barry之外,其他答案都没有。

但是,如果您希望读写访问您的最小和最大元素,为什么不直接使用minmax_element直接为您提供的迭代器呢? 至less如果你的lhs是一个ContiguousContainer但是也可能在其他情况下,它可能会生成与使用引用相同的机器码。

例如,您将需要减less自动types扣除,

 decltype(lhs.begin()) lhsMinIt, lhsMaxIt; std::tie(lhsMinIt, lhsMaxIt) = std::minmax_element(lhs.begin(), lhs.end()); /* now access your minimum and maximum as *lhsMinIt and *lhsMaxIt */ 

如果你知道lhs的types是标准容器的types,你可以使用一些更清晰的types名称decltype(lhs)::iterator

在C ++ 14或更高版本中

 template<class=void, std::size_t...Is> auto indexer( std::index_sequence<Is...> ) { return [](auto&&f){ return f( std::integral_constant<std::size_t, Is>{}... ); }; } template<std::size_t N> auto indexer() { return indexer( std::make_index_sequence<N>{} ); } template<class F> auto fmap_over_tuple( F&& f ) { return [f=std::forward<F>(f)](auto&& tuple) { using Tuple = decltype(tuple); using Tuple_d = std::decay_t<Tuple>; auto index = indexer< std::tuple_size< Tuple_d >::value >(); return index( [&f, &tuple](auto&&...Is) { using std::get; return std::make_tuple( f( get<Is>( std::forward<Tuple>(tuple) ) )... ); } ); }; } 

所以fmap_over_tuple需要一个函数对象。 它返回一个函数对象,当传递一个元组样式时,继续在元组的每个元素上调用函数对象,并从中产生一个元组。

然后我们编写解引用元组:

 auto dereference_tuple = fmap_over_tuple( [](auto&& e) { return *e; } ); 

现在在C ++ 17中,我们做:

 auto[Min, Max] = dereference_tuple( std::minmax_element(lhs.begin(), lhs.end() ); 

鲍勃是你的叔叔。

在C ++ 11中,只要做你做的。 清洁不够。

C ++ 14现场示例 。