std::transform和std::for_each之间有什么区别



两者都可以用于将函数应用于一系列元素。

高级:

  • std::for_each忽略函数的返回值,并且保证执行顺序
  • std::transform将返回值分配给迭代器,并执行不能保证执行的顺序

你更喜欢在什么时候使用这一种而不是另一种?有什么微妙的警告吗?

std::transformmap相同。其思想是将一个函数应用于两个迭代器之间的每个元素,并获得由应用该函数产生的元素组成的不同容器。您可能希望使用它,例如,将对象的数据成员投影到新容器中。在下文中,std::transform用于将std::strings的容器转换为std::size_ts的容器。

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循环,使用简洁的表示法也可以实现同样的效果:

for (std::size_t name_size: name_sizes) {
    std::cout << name_size << std::endl;
}

您的高级概览

  • std::for_each忽略函数的返回值并保证执行顺序
  • std::transform将返回值分配给迭代器,并且不保证执行顺序

几乎涵盖了它。

另一种看待它的方式(喜欢其中一种而不是另一种);

  • 运算的结果(返回值)重要吗
  • 对每个元素的操作是否都是一个没有返回值的成员方法
  • 是否有两个输入范围

需要记住的另一件事(微妙的警告)是std::transform在C++11之前和之后的操作需求的变化(来自en.cppreference.com);

  • 在C++11之前,他们被要求"没有任何副作用"
  • 在C++11之后,它改为"不得使任何迭代器无效,包括结束迭代器,或修改所涉及范围的任何元素"

基本上,这些都是为了允许不确定的执行顺序。

我什么时候使用一个而不是另一个

如果我想操作一个范围内的每个元素,那么我使用for_each。如果我必须从每个元素中计算一些东西,那么我会使用transform当使用for_eachtransform时,我通常将它们与lambda配对

也就是说,自从C++11中出现了基于范围的for循环和Lambda(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 like:实现同样的效果

std::for_each(s.begin(), s.end(), ::toupper);

它不会将其转换为大写字符串

相关内容

  • 没有找到相关文章

最新更新