std::valarray<int> numbers (15); // 15 elements with default initial values 0 std::valarray<size_t> sizes {1, 2, 3}; // 3 elements with values 1 2 and 3 std::valarray<size_t> copy_sizes {sizes}; // 3 elements with values 1 2 and 3 std::valarray<double> values; // Empty array std::valarray<double> data(3.14, 10); // 10 elements with values 3.14每個建構函式都生成了有給定元素數目的物件。在最後一條語句中,使用圓括號來定義 data 是必要的;如果使用花括號,data 會包含 3.14 和 10 兩個元素。也可以用從普通陣列得到的一定個數的值來初始化 valarray 物件。例如:
int vals[] {2, 4, 6, 8, 10, 12, 14}; std::valarray<int> valsl {vals, 5}; // 5 elements from vals: 2 4 6 8 10 std::valarray<int> vals2 {vals + 1, 4}; // 4 elements from vals: 4 6 8 10後面會介紹其他的建構函式,因為它們有一些必須解釋的引數型別。
data.resize(50, 1.5); // 50 elements with value 1.5在這個操作之前,如果 data 中儲存有元素,就會丟失它們的值。當需要得到元素的個數時,可以呼叫成員函數 size()。
std::valarray<size_t> sizes_3 {1, 2, 3}; std::valarray<size_t> sizes_4 {2, 3, 4, 5}; sizes_3.swap(sizes_4); // sizes_3 now has 4 elements and sizes_4 has 3valarray 物件中包含的元素個數可以不同,但顯然兩個物件中的元素必須是相同型別的。成員函數 swap() 沒有返回值。非成員函數 swap() 函數模板做的事是一樣的,因此最後一條語句可以替換為:
std::swap(sizes_3,sizes_4); // Calls sizes_3.swap(sizes_4)可以呼叫 valarray 的成員函數 min() 和 max() 來查詢元素的最小值和最大值。例如:
std::cout << "The elements are from " << sizes_4.min () << " to "<< sizes_4.max() << 'n';為了能夠正常工作,元素必須是支援 operator<() 的型別。
std::cout << "The average of the elements " << sizes_4.sum()/sizes_4.size() << 'n';這比使用 accumulate() 演算法要簡單得多。
std::valarray<int> d1 {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto d2 = d1.shift(2); // Shift left 2 positions for(int n : d2) std::cout << n <<' '; std::cout << 'n';//Result: 345678900 auto d3 = d1.shift(-3);//Shift right 3 positions std::copy(std::begin(d3), std::end(d3),std::ostream_iterator<int>{std::cout, " "}); std::cout << std::endl; // Result: 0 0 0 1 2 3 4 5 6註釋解釋發生了什麼。為了展示可以使用的輸出方式,在兩個範例中用了不同的方式來輸出結果。valarray 模板為物件定義了賦值運算子,所以如果想替換原始序列,可以這樣寫:
d1 = d1.shift(2); // Shift d1 left 2 positions元素移位的第二種方式是使用成員函數 cshift(),它會將元素序列迴圈移動由引數指定的數目的位置。序列會從左邊或右邊迴圈移動,這取決於引數是正數還是負數。這個成員函數也會返回一個新的物件。下面是一個範例:
std::valarray<int> d1 {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto d2 = d1.shift(2); // Result d2 contains: 3 4 5 6 7 8 9 1 2 auto d3 = d1.cshift(-3);// Result d3 contains: 7 8 9 1 2 3 4 5 6apply() 函數是 valarray 的一個非常強大的成員函數,它可以將一個函數應用到每個元素上,並返回一個新的 valarray 物件為結果。valarray 類別範本中定義了兩個 apply() 函數模板:
valarray<T> apply(T func(T)) const; valarray<T> apply(T func(const T&)) const;有三件事需要注意。第一,所有版本都是 const,所以函數不能修改原始元素。第二,引數是一個有特定形式的函數,這個函數以 T 型別或 T 的 const 參照為引數,並返回 T 型別的值;如果 apply() 使用的引數不符合這些條件,將無法通過編譯。第三,返回值是 valarray<T> 型別,因此返回值總是一個和原序列有相同型別和大小的陣列。
std::valarray<double> time {0.0,1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; // Seconds auto distances = time.apply([](double t) { const static double g {32.0}; // Acceleration due to gravity ft/sec/sec return 0.5*g*t*t; }); // Result: 0 16 64 144 256 400 576 784 1024 1296如果從高層建築向下丟磚塊,distances 物件可以計算出,過了相應的秒數後,磚塊下落了多少距離;為了使最後結果有效,建築的高度必須超過 1296 英尺。注意,不能使用從閉合區域捕獲的值作為引數的 lambda 表示式,因為這和函數模板中引數的規格不匹配。例如,下面的程式碼就無法通過編譯:
const double g {32.0}; auto distances = times.apply ([g] (double t) { return 0.5*g*t*t; }); // Won*t compile!在 lambda 表示式中以值捕獲 g 會改變它的型別,以至於它不符合應用模板的規範。對於可以作為 apply() 引數的 lambda 表示式,捕獲語句必須為空。必須有一個和陣列型別相同的引數,並返回一個這種型別的值。
abs(), pow(), sqrt(), exp(), log(), log10(), sin(), cos(), tan(), asin(), acos(), atan(), atan2(), sinh(),cosh(), tanh()
下面是一個將這一節的程式碼段組合到一起的範例,它提供了一次將 cmath 函數用到 valarray 物件上的機會:// Dropping bricks safely from a tall building using valarray objects #include <numeric> // For iota() #include <iostream> // For standard streams #include <iomanip> // For stream manipulators #include <algorithm> // For for_each() #include <valarray> // For valarray const static double g {32.0}; // Acceleration due to gravity ft/sec/sec int main() { double height {}; // Building height std::cout << "Enter the approximate height of the building in feet: "; std::cin >> height; // Calculate brick flight time in seconds double end_time {std::sqrt(2 * height / g)}; size_t max_time {1 + static_cast<size_t>(end_time + 0.5)}; std::valarray<double> times(max_time + 1); // Array to accommodate times std::iota(std::begin(times), std::end(times), 0); // Initialize: 0 to max_time *(std::end(times) - 1) = end_time; // Set the last time value // Calculate distances each second auto distances = times.apply([](double t) { return 0.5*g*t*t; }); // Calculate speed each second auto v_fps = sqrt(distances.apply([](double d) { return 2 * g*d; })); // Lambda expression to output results auto print = [](double v) { std::cout << std::setw(5) << static_cast<int>(std::round(v)); }; // Output the times - the last is a special case... std::cout << "Time (seconds): "; std::for_each(std::begin(times), std::end(times) - 1, print); std::cout << std::setw(5) << std::fixed << std::setprecision(2) << *(std::end(times) - 1); std::cout << "nDistances(feet):"; std::for_each(std::begin(distances), std::end(distances), print); std::cout << "nVelocity(fps): "; std::for_each(std::begin(v_fps), std::end(v_fps), print); // Get velocities in mph and output them auto v_mph = v_fps.apply([](double v) { return v * 60 / 88; }); std::cout << "nVelocity(mph): "; std::for_each(std::begin(v_mph), std::end(v_mph), print); std::cout << std::endl; }這樣就能夠確定從高層建築丟下磚塊時發生了什麼。下面是一些從迪拜塔得到的範例輸出,為了避免磚塊撞到牆壁,假設是從一根足夠長的桿子上扔下磚塊的:
Enter the approximate height of the building in feet: 2722
Time (seconds) : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 13.04
Distances(feet): 0 16 64 144 256 400 576 784 1024 1296 1600 1936 2304 2704 2722
Velocity (fps) : 0 32 64 96 128 160 192 224 256 288 320 352 384 416 417
Velocity (mph) : 0 22 44 65 87 109 131 153 175 196 218 240 262 284 285
[]
,但下標運算子可以做的事不止於此,在本章的後面你就會看到。