[英]What is the difference between std::transform and std::for_each?
兩者都可用於將函數應用於一系列元素。
在高層次上:
std::for_each
忽略函數的返回值,並保證執行順序。 std::transform
將返回值賦給迭代器,並不保證執行的順序。 你什么時候喜歡使用那個? 有任何微妙的警告嗎?
std::transform
與map
相同。 我們的想法是將函數應用於兩個迭代器之間的每個元素,並獲得由應用此類函數產生的元素組成的不同容器。 您可能希望將其用於,例如,將對象的數據成員投影到新容器中。 在下文中, std::transform
用於在std::size_t
s的容器中轉換std::string
的容器。
std::vector<std::string> names = {"hi", "test", "foo"};
std::vector<std::size_t> name_sizes;
std::transform(names.begin(), names.end(), std::back_inserter(name_sizes), [](const std::string& name) { return name.size();});
另一方面,您執行std::for_each
作為唯一的副作用。 換句話說, std::for_each
非常類似於基於范圍的普通for
循環。
回到字符串示例:
std::for_each(name_sizes.begin(), name_sizes.end(), [](std::size_t name_size) {
std::cout << name_size << std::endl;
});
實際上,從C ++ 11開始,使用基於范圍的for
循環的terser表示法可以實現相同的目的:
for (std::size_t name_size: name_sizes) {
std::cout << name_size << std::endl;
}
您的高級概述
std::for_each
忽略函數的返回值並保證執行順序。std::transform
將返回值賦給迭代器,並不保證執行的順序。
幾乎涵蓋了它。
另一種看待它的方式( 優先選擇另一種方式);
還要記住的另一件事( 微妙的警告 )是在C ++ 11之前和之后(來自en.cppreference.com) std::transform
操作要求的變化;
基本上這些是允許未確定的執行順序。
我何時使用一個而不是另一個?
如果我想操作范圍中的每個元素,那么我使用for_each
。 如果我必須從每個元素計算一些東西,那么我會使用transform
。 當使用for_each
和transform
,我通常將它們與lambda配對。
也就是說,我發現自從C ++ 11中基於for
循環和lambdas的范圍的出現( for (element : range)
)以來,我對傳統for_each
當前用法有所減少。 我發現它的語法和實現非常自然(但你的里程數會有所不同),並且更適合某些用例。
雖然問題已得到解答,但我相信這個例子可以進一步澄清這一區別。
for_each
屬於非修改STL操作 ,這意味着這些操作不會更改集合的元素或集合本身。 因此, for_each返回的值始終被忽略,並且不會分配給集合元素 。 盡管如此,仍然可以修改集合的元素,例如,當使用引用將元素傳遞給f函數時。 人們應該避免這種行為,因為它與STL原則不一致。
相反, transform
函數屬於修改STL操作 ,並將給定謂詞(unary_op或binary_op)應用於集合或集合的元素,並將結果存儲在另一個集合中。
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
void printer(int i) {
cout << i << ", ";
}
int main() {
int mynumbers[] = { 1, 2, 3, 4 };
vector<int> v(mynumbers, mynumbers + 4);
for_each(v.begin(), v.end(), negate<int>());//no effect as returned value of UnaryFunction negate() is ignored.
for_each(v.begin(), v.end(), printer); //guarantees order
cout << endl;
transform(v.begin(), v.end(), v.begin(), negate<int>());//negates elements correctly
for_each(v.begin(), v.end(), printer);
return 0;
}
將打印:
1, 2, 3, 4,
-1, -2, -3, -4,
使用std :: tranform的真實示例是,當您想要將字符串轉換為大寫時,您可以編寫如下代碼:
std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);
如果你試圖用std :: for_each來實現同樣的東西:
std::for_each(s.begin(), s.end(), ::toupper);
它不會將其轉換為大寫字符串
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.