web-dev-qa-db-ja.com

C ++ 17:タプルをアンパックするときに一部のメンバーのみを保持する

次のメソッドを呼び出す必要があると想像してください。

std::Tuple<int, int, int> foo();

C++ 17では、関数を呼び出して、タプルを1行でアンパックできます。

auto [a, b, c] = foo();

さて、どうすればbcのみを保存し、aを破棄できますか?

現在、私は2つのオプションしか認識していません。


1-自動展開時にダミー変数を使用できます

ただし、ダミー変数は使用されず、警告が発行されるため、警告を表示したくない場合、コードを見るのは非常に不快です。

#pragma warning(Push)
#pragma warning(disable:4101)
// ReSharper disable once CppDeclaratorNeverUsed
auto [_, b, c] = foo();
#pragma warning(pop)

2-タプル全体を保存し、std::getを使用して、必要な変数のみへの参照を取得できます。コードはそれほど不快ではありませんが、構文はそれほど単純ではありません。

さらに、このコードのサイズは、タプルに保持する新しい値ごとに1行ずつ増加します。

auto Tuple = foo();
int b = std::get<1>(Tuple);
int c = std::get<2>(Tuple);

タプルの一部のパラメータのみをアンパックする別のより簡単な方法はありますか?

63
Antoine C.

別の方法は、std::tieを使用することです:

int b, c;
std::tie(std::ignore, b, c) = foo();

編集

コメントで述べたように、このアプローチにはいくつかの問題があります。

  • 型の推論は不可能
  • オブジェクトは前に構築する必要があるため、デフォルトのコンストラクターが簡単でない限り、これは適切な代替手段ではありません。
42
Mansuro

残念ながら structured bindings はメンバーの破棄を明示的にサポートしておらず、 [[maybe_unused]] などの属性は構造化バインディング(その提案があります: P0609: "構造化バインディングの属性" ) 。

考えられる解決策は次のとおりです。

auto [a, b, c] = foo();
(void) a; // unused
39
Vittorio Romeo

std::Tupleの特定のインデックスのみを返すヘルパー関数を作成できます。

template <size_t... Is, typename Tuple>
auto take_only(Tuple&& Tuple) {
    using T = std::remove_reference_t<Tuple>;

    return std::Tuple<std::Tuple_element_t<Is, T>...>(
        std::get<Is>(std::forward<Tuple>(Tuple))...);
}

auto [b, c] = take_only<1, 2>(foo());

または、頭か何かを落とします:

template <size_t... Is, typename Tuple>
auto drop_head_impl(Tuple&& Tuple, std::index_sequence<0, Is...> ) {
    return take_only<Is...>(std::forward<Tuple>(Tuple));
}

template <typename Tuple>
auto drop_head(Tuple&& Tuple) {
    return drop_head_impl(std::forward<Tuple>(Tuple),
        std::make_index_sequence<std::Tuple_size_v<std::decay_t<Tuple>>>());
}

auto [b, c] = drop_head(foo());

しかし、上記の実装には、構造化バインディングを直接使用することで発生しない寿命の複雑さの問題がほぼ確実にあります。ここには寿命の拡張機能がないためです。

それで、ちょうど Vittorioが言う

auto [a, b, c] = foo();
(void)a;
21
Barry

VS 15.7プレビューでは、MSVCにはすでに fixed thisがあります。最終的な15.7リリースは、今後数週間で利用可能になります。つまり、すべての主要なコンパイラの最新リリースでサポートされている現在のロジックは次のとおりです。

  • 構造化バインディング宣言内の少なくとも1つの構造化バインディングが使用されている場合、同じ宣言内の他のバインディングに対して「未使用変数」警告は発行されません。
  • 構造化バインディング宣言内のバインディングのいずれも使用されていない場合、[[maybe_unused]]属性を使用して、警告を黙らせることができます。

    [[maybe_unused]] auto [a、b、c] = foo();
5
Igor Akhmetov