ベクトルで構造化バインディングを使用することはできますか?
例えば。
std::vector<int> vec{1, 2, 3};
auto [a, b, c] = vec;
上記のコードは残念ながら動作しません(GCCの下)が、ベクトルの最初の3つの値を3つの変数に割り当てることができる別の方法(構造化バインディング)がある場合があります。
構造化バインディングは、コンパイル時に構造がわかっている場合にのみ機能します。これはvector
には当てはまりません。
個々の要素の構造は知っていますが、要素の数はわかりません。それがあなたの質問で分解しようとしていることです。同様に、コンパイル時にサイズがわかっている配列タイプでのみ構造化バインディングを使用できます。考慮してください:
void f(std::array<int, 3> arr1,
int (&arr2)[3],
int (&arr3)[])
{
auto [a1,b1,c1] = arr1;
auto [a2,b2,c2] = arr2;
auto [a3,b3,c3] = arr3;
}
最初の2つは機能しますが、最後の行はコンパイルに失敗します。arr3
はコンパイル時にはわかりません。 ゴッドボルトで試してみてください 。
タプルのようにアクセスできる基本的なラッパーをベクターに作成するのは簡単です。コンパイル時にベクターのサイズを取得する方法は実際にないため、ベクターが短すぎる構造を解こうとすると、std::out_of_range
がスローされます。残念ながら、要求されたバインディングの数を推測する方法がわからないので、それは明白です。
完全なコード:
#include <string>
#include <vector>
#include <iostream>
template <class T, std::size_t N>
struct vector_binder {
std::vector<T> &vec;
template <std::size_t I>
T &get() {
return vec.at(I);
}
};
namespace std {
template<class T, std::size_t N>
struct Tuple_size<vector_binder<T, N>>
: std::integral_constant<std::size_t, N> { };
template<std::size_t I, std::size_t N, class T>
struct Tuple_element<I, vector_binder<T, N>> { using type = T; };
}
template <std::size_t N, class T>
auto dissect(std::vector<T> &vec) {
return vector_binder<T, N>{vec};
}
int main() {
std::vector<int> v{1, 2, 3};
auto [a, b] = dissect<2>(v);
a = 5;
std::cout << v[0] << '\n'; // Has changed v through a as expected.
}
vector_binder
の右辺値とconstバージョン、およびより良い名前は、読者への演習として残されています:)
より冗長なので理想的ではありませんが、次のこともできます。
auto [a, b, c] = array<int, 3>({vec[0], vec[1], vec[2]});
コンテナの要素の数を知らないことが、その要素への構造化されたバインディングを妨げるべきであるという考えには同意しません。私の理由は、以下はコンパイル時エラーをスローしないからです:
auto a = vec[0];
auto b = vec[1];
auto c = vec[2];
(たとえvec [2]が実行時に範囲外であったとしても)、上記の構造化バインディングの場合はそうである必要があります。つまり、実行時にベクトルの長さが正しいことを確認し、そうでない場合は範囲外の例外をスローするようユーザーに任せてみませんか?それは基本的に、言語のどこでもベクターを使用する方法です。