STLのvalarrayを知った

Twitterで知っていろいろ触ってみました.std::valarray.std::vectorなどとは大きく使い勝手が違うので,使うときは注意が必要です.

何に使うクラス?

複数の数値それぞれに対して同じ計算を一斉にやりたいときに便利.

基本

// C++11
std::valarray<int>
    foo = {1, 4, 3, 2},
    bar = {5, 2, 0, 3};

foo.size(); // => 4
foo.max(); // => 4
foo.min(); // => 1

// 以下,{...}はstd::valarray<int>({...})の略
foo * 2; // => {2, 8, 6, 4}
foo + bar; // => {6, 6, 3, 5}
foo -= 3; // 破壊的変更
foo; // => {-2, 1, 0, -1}

foo.apply([](int x) { return x*x; });
    // => {1, 16, 9, 4}; 非破壊的
foo.apply(std::abs); // => {2, 1, 0, 1}; 要cstdlib
std::abs(foo); // foo.apply(std::abs)と同義

bar.shift(3); // => {3, 0, 0, 0}; 非破壊的
bar.cshift(3); // => {3, 5, 2, 0}; 非破壊的

応用

このクラスにはイテレータがありません.要素を部分的に変更したい場合は普通の添え字アクセスの他に,便利なアクセス法が用意されています.

std::valarray<int> hoge = {0, 1, 2, 3, 4, 5};
const std::valarray<int> fuga = hoge;

hoge[2] = 0; // => {0, 1, 0, 3, 4, 5}; 破壊的
hoge[std::slice(1, 3, 2)] // => hoge[1], hoge[3], hoge[5]への参照
hoge[std::slice(1, 3, 2)] += 1;
    // => {0, 2, 0, 4, 4, 6}; 破壊的
fuga[std::slice(1, 3, 2)] // => valarray<int>({1, 3, 5})

sliceの他にもあるので,詳しくはhttp://www.cplusplus.com/reference/valarray/valarray/operator[]/で

よくわからないところ

std::valarray<int> ary = {0, 1, 2};

for (auto &x : ary); // 可
for (auto &x : ary * 2); // 不可
for (auto &x : ary[slice(0, 2, 1)]); // 不可
for (auto 6x : valarray<int>(ary * 2)); // 可
for (auto &x : valarray<int>(ary[slice(0, 2, 1)])); // 可

僕が仕様読んでる限りはary * 2やary[slice(0, 2, 1)]はvalarrayのインスタンスを返すはずなんですけど.そもそもイテレータが無いのにrange-based forで列挙できるのも変な話ですが.単なる勘違いかもしれません.