C++ iota函數用法詳解

2020-07-16 10:04:32
定義在 numeric 標頭檔案中的 iota() 函數模板會用連續的 T 型別值填充序列。前兩個引數是定義序列的正向疊代器,第三個引數是初始的 T 值。第三個指定的值會被儲存到序列的第一個元素中。儲存在第一個元素後的值是通過對前面的值運用自增運算子得到的。當然,這意味著 T 型別必須支援 operator++()。下面展示了如何生成一個有連續的浮點值元素的 vector 容器:
std::vector<double> data(9);
double initial {-4};
std::iota (std::begin (data) , std::end (data) , initial);
std::copy(std::begin(data), std::end(data),std::ostream_iterator<double>{std::cout<< std::fixed << std::setprecision(1), " "});
std::cout << std::endl;  // -4.0 -3.0 -2.0 -1.0 0.0 1.0 2.0 3.0 4.0
以 4 為初始值呼叫 iota() 會將 data 中元素的值設為從 -4 到 +4 的連續值。當然,初始值並不需要一定是整數:
std::iota(std::begin(data), std::end(data), -2.5);
// Values are -2.5 -1.5 -0.5 0.5 1.5 2.5 3.5 4.5 5.5
增量是 1,因此 data 中的值和注釋顯示的一樣。可以將 iota() 演算法應用到任意型別的序列上,只要它有自增運算子。下面是另一個範例:
string text {"This is text"};
std::iota(std::begin(text), std::end(text), 'K');
std::cout << text << std::endl;   // Outputs: KLMNOPQRSTUV
很容易看到輸出如注釋所示,字串中的字元被設為以 K 開頭的字元序列。這個範例發生了什麼並不是那麼明顯:
std::vector<string> words (8);
std::iota(std::begin(words), std::end(words), "mysterious");
std::copy(std::begin(words), std::end(words),std::ostream_iterator<string>{std::cout, " "});
std::cout << std::endl; // mysterious ysterious sterious terious erious rious ious ous
輸出如注釋所示。這是該演算法的一個有趣應用,但沒有什麼用處。這只適用於第三個引數是一個字串常數的情形。如果引數是 string{"mysterious"},將無法通過編譯,因為沒有為 string 類定義 operator++()。字串常數對應的值是一個 const char* 型別的指標,可以將 ++ 運算子應用到它上面。因此對於 words 中第一個元素後的每個元素,指標的遞增會導致字串常數前面的字母被丟棄。將 ++ 應用到指標的結果是生成一個 string 物件,然後它會被儲存到當前的元素序列中。只要 ++ 可以應用到序列中的元素型別上,就能將 iota() 演算法應用到序列上。

注意:很有趣的是,iota() 演算法來源於 IBM 的程式語言 APL 中的 iota 運算子 ι。在 APL 中,表示式 ι10 會生成從 1 到 10 的整數的 vector。APL 是肯•艾弗森在 20 世紀 60 年代發明的。它是一門相當筒潔的語言,能夠隱式處理 vector 和陣列。APL 的一個完整程式會從鍵盤讀取任意個值,計算出它們的平均值,然後輸出被表示為 10 個字元結果。