33

C++11 にはstd::minmax_element、値のペアを返す関数があります。ただし、これは処理と読み取りが非常に混乱し、後で役に立たない余分な変数が生成されてスコープが汚染されます。

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()));
4

6 に答える 6

23

スコープの汚染を避けるために、割り当てをより小さなスコープで囲むことができます。

int lhsMin, lhsMax;

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

または、ラムダを使用できます

int lhsMin, lhsMax;

std::tie(lhsMin, lhsMax) = [&]{
    auto it = std::minmax_element(lhs.begin(), lhs.end());
    return std::make_tuple(*it.first, *it.second);
}();
于 2016-10-27T11:16:07.557 に答える
13

これは、ヘルパー関数を呼び出すのに十分な一般的なケースのように見えます。

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 で行うことができます

注: SFINAE を適用できるように、C++14 でも繰り返しdecltypeinの戻り値の型を保持します。deref

Coliruでライブを見る

于 2016-10-27T11:36:29.030 に答える
2

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 のライブ例

于 2016-10-28T00:01:04.040 に答える