最近私は自分のコードでspan<T>
を使うことを提案するか、あるいはここでspan
を使う答えを見ました - おそらくある種のコンテナです。しかし、C++標準ライブラリにはそのようなものはありません。
それで、この不思議なspan<T>
は何ですか、そしてそれが標準的でないならなぜそれを使うのが良い考えですか(そしていつ)
span<T>
は次のとおりです。
struct { T * ptr; size_t length; }
。以前は array_view
として知られていましたが、以前は array_ref
として知られていました。
まず、notがそれを使うとき:
std::sort
、std::find_if
、std::copy
、およびこれらのすべてのスーパージェネリックテンプレート関数のように、任意の開始および終了反復子のペアを受け取ることができるコードでは使用しないでください。それを実際に使うときのために
長さの値がある独立した
span<T>
(それぞれspan<const T>
)の代わりにT*
(それぞれconst T*
)を使用します。そのため、次のような関数を置き換えます。void read_into(int* buffer, size_t buffer_size);
と:
void read_into(span<int> buffer);
ああ、スパンは素晴らしいです! span
...を使用する.
あなたが空想の、くっきりとした標準ライブラリコンテナを使うのと同じように、あなたはそのポインタ+長さ/開始+終了ポインタの組み合わせで働くことができることを意味します。
for (auto& x : my_span) { /* do stuff */ }
std::find_if(my_span.begin(), my_span.end(), some_predicate);
...しかし、ほとんどのコンテナクラスで発生するオーバーヘッドはまったくありません。
コンパイラがあなたのためにもっと多くの仕事をすることを可能にします。たとえば、
int buffer[BUFFER_SIZE];
read_into(buffer, BUFFER_SIZE);
これになります:
int buffer[BUFFER_SIZE];
read_into(buffer);
...あなたがやりたいことをやります。 ガイドラインP.5 もご覧ください。
データがメモリ内で連続していることが予想されるときにconst vector<T>&
を関数に渡すことに対する合理的な代替方法です。これ以上に強力なC++の達人に叱られることはもうありません。
span
のメソッドは、#ifndef NDEBUG
... #endif
内にいくつかの境界チェックコードを持ちます)。C++のコアガイドライン で見つけることができるspan
sを使う動機はさらにあります - しかし、あなたはそのドリフトに気付きます。
これは標準ライブラリにありますが、C++ 20以降に限られます。その理由は、現在の形ではまだかなり新しいことであり、2015年以来形作られてきた C++コアガイドライン プロジェクトとの関連で考え出されています。
これは Core Guidelines のSupport Library(GSL)の一部です。実装:
gsl/span
span<T>
を含め、GSL全体を単一ファイルで実装したものです(それほど大きくはありません、心配しないでください)。C++ 17だけではなく、C++ 11およびC++ 14の言語標準の以前のバージョンでも使用できます。
さらに読むこと: C++ 17、P0122R7の前の最後の公式の提案で詳細と設計上の考慮点をすべて見つけることができます: span:オブジェクトシーケンス に対する境界安全なビュー[] Neal MacintoshとStephan J.Lavavej。それは少し長いです。また、C++ 20では、スパン比較セマンティクスが変更されました(Tony van Eerdによる this short paper の後)。