簡體   English   中英

std :: transform和std :: for_each有什么區別?

[英]What is the difference between std::transform and std::for_each?

兩者都可用於將函數應用於一系列元素。

在高層次上:

  • std::for_each忽略函數的返回值,並保證執行順序。
  • std::transform將返回值賦給迭代器,並不保證執行的順序。

你什么時候喜歡使用那個? 有任何微妙的警告嗎?

std::transformmap相同。 我們的想法是將函數應用於兩個迭代器之間的每個元素,並獲得由應用此類函數產生的元素組成的不同容器。 您可能希望將其用於,例如,將對象的數據成員投影到新容器中。 在下文中, 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操作要求的變化;

  • 在C ++ 11之前,他們被要求“沒有任何副作用”,
  • 在C ++ 11之后,這變為“必須不使任何迭代器無效,包括結束迭代器,或修改所涉及范圍的任何元素”

基本上這些是允許未確定的執行順序。

我何時使用一個而不是另一個?

如果我想操作范圍中的每個元素,那么我使用for_each 如果我必須從每個元素計算一些東西,那么我會使用transform 當使用for_eachtransform ,我通常將它們與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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM