Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::transform和std::for_之间的区别是什么?_C++_C++11_Stl Algorithm - Fatal编程技术网

C++ std::transform和std::for_之间的区别是什么?

C++ std::transform和std::for_之间的区别是什么?,c++,c++11,stl-algorithm,C++,C++11,Stl Algorithm,两者都可用于将函数应用于一系列元素 在高级别上: std::for_each忽略函数的返回值,并且 保证执行的秩序 std::transform将返回值赋给迭代器,并执行以下操作 不保证执行的顺序 你什么时候比较喜欢用一个还是另一个?有什么微妙的警告吗?使用std::tranform的真实示例是,当您想将字符串转换为大写时,可以编写如下代码: std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper); 如果

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

在高级别上:

  • std::for_each
    忽略函数的返回值,并且 保证执行的秩序
  • std::transform
    将返回值赋给迭代器,并执行以下操作 不保证执行的顺序

你什么时候比较喜欢用一个还是另一个?有什么微妙的警告吗?

使用std::tranform的真实示例是,当您想将字符串转换为大写时,可以编写如下代码:

std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);
如果您将尝试使用std::for_实现相同的目标,请选择:

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

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

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

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();});
事实上,从C++11开始,同样可以通过使用基于范围的
for
循环的更简洁的表示法来实现:

for (std::size_t name_size: name_sizes) {
    std::cout << name_size << std::endl;
}
for(std::size\u t name\u size:name\u size){

std::cout您的高级概述

  • std::for_each
    忽略函数的返回值并保证执行顺序
  • std::transform
    将返回值分配给迭代器,但不保证执行顺序
差不多涵盖了它

另一种看待它的方式(选择一种而不是另一种)

  • 操作的结果(返回值)重要吗
  • 对每个元素的操作都是没有返回值的成员方法吗
  • 有两个输入范围吗
需要记住的另一件事(微妙的警告)是C++11之前和之后的操作要求的变化(来自en.cppreference.com)

  • 在C++11之前,他们被要求“没有任何副作用”
  • 在C++11之后,它改为“不得使任何迭代器(包括结束迭代器)无效,或修改所涉及范围的任何元素”
基本上,这些都是为了允许不确定的执行顺序

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

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

也就是说,自从C++11中基于范围的
for
循环和lambda(
for(element:range)
)出现以来,我发现我目前对传统
for_each
的使用有所减少。我发现它的语法和实现非常自然(但您在这里的里程数会有所不同)更直观地适用于某些用例。

虽然这个问题已经得到了回答,但我相信这个例子将进一步澄清两者之间的区别

for_each
属于非修改STL操作,这意味着这些操作不会更改集合的元素或集合本身。因此,for_each返回的值始终被忽略,并且不会分配给集合元素。 尽管如此,仍然可以修改集合的元素,例如当使用引用将元素传递给f函数时。应避免此类行为,因为它与STL原则不一致

相反,
transform
函数属于修改STL操作,将给定谓词(一元谓词或二元谓词)应用于一个或多个集合的元素,并将结果存储在另一个集合中

#包括
#包括
#包括
#包括
使用名称空间std;
无效打印机(int i){

cout
transform
有一个输出范围,而
对于每个
都没有。很多
由非常相似的函数组成,只是有一些细微的差别。@o11c这正是我要寻找的。产生细微差别一定有很好的原因。@bendervader的要点是:
被大量使用。方便是关键整个头的最大(如果不仅仅是)激励因素。许多采用可调用的算法都必须处理
void
返回值,您是否尝试过将
void
赋值给任何对象?为了扩展这一点,在C++14中,我们可以将类型从基于for循环的范围中删除,现在为:for(name_size:name_size){…}@TrevorHickey我很快又检查了一遍,除了最初的提案N3853之外,我找不到任何消息。你确定吗?我错了。这不是C++14的一部分,但它将是C++17的一部分。你现在可以在Clang/GCC上运行它,只要有正确的标志:不完全正确。
std::for_each
并不意味着有副作用,即修改t正如另一位用户所指出的那样,通过引用使用容器。这与该用户所指出的原则不一致。我不同意您对副作用(“即”部分)的定义。将任何信息打印到控制台是一个典型的示例(如果不是“示例”)副作用。事实上,这与您可能提到的@bugshotgg的解释是一致的。请您详细说明一下为什么“std::transform…不能保证执行顺序”?这与每个算法的
不同,它要求将函数按顺序应用于每个元素。
转换
操作要求没有任何副作用,这意味着执行顺序不可观察,因此无法保证。总之,我已经研究了所有实现
for (std::size_t name_size: name_sizes) {
    std::cout << name_size << std::endl;
}