web-dev-qa-db-ja.com

構造化バインディングの使用例は何ですか?

C++ 17標準は新しい 構造化バインディング 機能を導入します。これは2015年に最初に 提案 であり、その構文の外観は広く 議論されました 後でありました。

ドキュメントを見るとすぐに、それらの使用法がいくつか思い浮かびます。

集計分解

タプルを宣言しましょう:

std::Tuple<int, std::string> t(42, "foo");

名前付きの要素ごとのコピーは、1行で構造化されたバインディングを使用して簡単に取得できます。

auto [i, s] = t;

これは次と同等です:

auto i = std::get<0>(t);
auto s = std::get<1>(t);

または

int i;
std::string s;
std::tie(i, s) = t;

Tuple要素への参照も簡単に取得できます。

auto& [ir, sr] = t;
const auto& [icr, scr] = t;

したがって、すべてのメンバーがパブリックである配列または構造体/クラスを使用できます。

複数の戻り値

上記のすぐ後に、関数から複数の戻り値を取得する便利な方法があります。

他に何がありますか?

構造化バインディングのその他の、おそらくあまり目立たない使用例を提供できますか?他にどのようにしてC++コードの可読性やパフォーマンスを改善できるでしょうか?

注意事項

コメントで述べたように、構造化バインディングの現在の実装にはいくつかの機能がありません。それらは非可変であり、それらの構文は集約メンバーを明示的にスキップすることを許可しません。 ここ 多様性についての議論を見つけることができます。

22
Sergey

構造化バインディングのその他の、おそらくあまり明確ではない使用例を提供できますか?他にどのようにしてC++コードの可読性やパフォーマンスを向上させることができますか?

より一般的には、それを使用して(私に言わせて)npack構造にして、それから変数のセットを埋めることができます。

struct S { int x = 0; int y = 1; };

int main() {
    S s{};
    auto [ x, y ] = s;
    (void)x, void(y);
}

逆の方法は次のようになります。

struct S { int x = 0; int y = 1; };

int main() {
    S s{};
    auto x = s.x;
    auto y = s.y;
    (void)x, void(y);
}

配列でも同じことが可能です:

int main() {
    const int a[2] = { 0, 1 };
    auto [ x, y ] = a;
    (void)x, void(y);
}

とにかく、関数から構造または配列を返すときにも機能するので、おそらくこれらの例は、すでに述べたのと同じケースのセットに属していると主張できます。


@TobiasRibizelによる回答へのコメントで言及されているもう1つの良い例は、コンテナーを反復処理して内容物を簡単に解凍する可能性です。
例としてstd::map

#include <map>
#include <iostream>

int main() {
    std::map<int, int> m = {{ 0, 1 }, { 2, 3 }};
    for(auto &[key, value]: m) {
        std::cout << key << ": " << value << std::endl;
    }
}
16
skypjack

構造化バインディングのその他の、おそらくあまり明確ではない使用例を提供できますか?

これらは、構造体のget<N>を実装するために使用できます- magic_getの自動生成されたcore17_generated.hpp を参照してください。これは、静的なリフレクションのプリミティブ形式を提供するため便利です(たとえば、struct)のすべてのメンバーを反復します

9
Vittorio Romeo

反対の証拠がなければ、構造化バインディングはレガシーAPIを処理するための手段に過ぎないと思います。私見、SBを必要とするAPIは代わりに修正されるべきでした。

したがって、代わりに

auto p = map.equal_range(k);
for (auto it = p.first; it != p.second; ++it)
    doSomethingWith(it->first, it->second);

私たちは書くことができるはずです

for (auto &e : map.equal_range(k))
    doSomethingWith(e.key, e.value);

の代わりに

auto r = map.insert({k, v});
if (!r.second)
    *r.first = v;

私たちは書くことができるはずです

auto r = map.insert({k, v});
if (!r)
    r = v;

等.

確かに、誰かがある時点で賢い使い方を見つけるでしょうが、私にとって、それらについて知って1年経っても、それらはまだ未解決の謎です。特にこの論文はBjarneによって共同執筆されたため、Bjarneは通常、適用範囲が狭い機能を紹介することで知られていません。

1