一、transform 和 for_each 算法的区别
1、transform 和 for_each 算法作用区别
for_each 算法 主要用于 对容器中的每个元素执行某种操作 , 而不一定产生新的值或改变原容器的值 , 可能涉及改变元素的值 , 输出元素的值等 ; 使用该算法常用于 遍历输出到控制台 操作 或 修改原容器中的元素内容 操作 ;
transform 算法 主要用于 对容器中的每个元素进行转换 , 并将结果存储到另一个容器中 , 其执行的是一对一的映射操作 ; 会生成新的序列 , 或者在原地修改序列 ;
2、transform 和 for_each 算法 返回值区别
transform 算法 返回一个迭代器 , 指向输出序列的最后一个元素的下一个位置 , 如果提供了 输出迭代器 , 则 transform 不保证 原容器 的内容不变 ;
for_each 算法 返回一个函数对象 , 一般情况下不会使用该返回值 , for_each 的主要目的是执行遍历操作 , 而不是产生新的序列或返回值 ;
3、transform 和 for_each 算法 接收的 函数对象 参数 和 返回值区别
for_each 算法 接收 的 函数对象 的 参数 一般都是 引用参数 , 返回值为 void ;
transform 算法 接收 的 函数对象 的 参数 一般都是 值参数 , 返回值 必须有类型 , 是输出容器元素类型 ;
二、STL 算法接收的可调用对象分析 - 以 transform 为例进行分析
1、参考代码示例
在下面的代码中 ,
首先 , 创建了一个 vector 数组容器 ,
代码语言:javascript复制 // 创建一个 vector 数组容器
vector<int> myVector;
// 向容器中插入元素
myVector.push_back(9);
myVector.push_back(5);
myVector.push_back(2);
myVector.push_back(7);
然后 , 使用 transform 算法为每个容器中的元素进行自增操作 , 将自增的元素继续输出到 原来的 数组容器中 ;
代码语言:javascript复制 // 向 transform 变换算法中 传入 Lambda 表达式
transform(myVector.begin(), myVector.end(), myVector.begin(), [](int element) {
return element;
});
最后 , 使用 for_each 算法遍历 vector 数组容器 , 查看 transform 变换后的结果 ;
代码语言:javascript复制 // 遍历容器
for_each(myVector.begin(), myVector.end(), [](int element) {
cout << element << endl;
});
代码示例 :
代码语言:javascript复制#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"
int main() {
// 创建一个 vector 数组容器
vector<int> myVector;
// 向容器中插入元素
myVector.push_back(9);
myVector.push_back(5);
myVector.push_back(2);
myVector.push_back(7);
// 向 transform 变换算法中 传入 Lambda 表达式
transform(myVector.begin(), myVector.end(), myVector.begin(), [](int element) {
return element;
});
// 遍历容器
for_each(myVector.begin(), myVector.end(), [](int element) {
cout << element << endl;
});
// 控制台暂停 , 按任意键继续向后执行
system("pause");
return 0;
};
执行结果 :
代码语言:javascript复制10
6
3
8
请按任意键继续. . .
2、transform 函数接收的规则
将 transform 函数的 Lambda 表达式 的 返回值注释掉 ,
代码语言:javascript复制 // 向 transform 变换算法中 传入 Lambda 表达式
transform(myVector.begin(), myVector.end(), myVector.begin(), [](int element) {
//return element;
});
将 接收 int 参数 , 返回 int 返回值 的 Lambda 表达式 ,
代码语言:javascript复制int(int)
变成了 接收 int 参数 , 返回 void 的 Lambda 表达式 ;
代码语言:javascript复制void(int)
此时编译时 , 报如下错误 :
代码语言:javascript复制1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
1>Test.cpp
1>C:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.24.28314includealgorithm(1310,1): error C2440: “=”: 无法从“void”转换为“int”
1>C:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.24.28314includealgorithm(1310,24): message : void 类型的表达式不能转换为其他类型
1>Y: 02_WorkSpace 02_VSHelloWorldHelloWorldTest.cpp(21): message : 查看对正在编译的函数 模板 实例化“_OutIt std::transform<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,main::<lambda_3c270406302a4dd5e2ba2daa1c0faf8f>>(const _InIt,const _InIt,_OutIt,_Fn)”的引用
1> with
1> [
1> _OutIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>,
1> _Ty=int,
1> _InIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>,
1> _Fn=main::<lambda_3c270406302a4dd5e2ba2daa1c0faf8f>
1> ]
1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
3、查看算法函数接收的可调用对象 - 以 transform 函数为例
查看 transform 函数的源码 如下 :
代码语言:javascript复制// FUNCTION TEMPLATE transform
template <class _InIt, class _OutIt, class _Fn>
_OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func) {
// transform [_First, _Last) with _Func
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));
for (; _UFirst != _ULast; _UFirst, (void) _UDest) {
*_UDest = _Func(*_UFirst);
}
_Seek_wrapped(_Dest, _UDest);
return _Dest;
}
在上述 transform 源码中 , 传入的可调用对象是 _Fn _Func 参数 , 在代码中 , 会调用该 可调用对象 , 并返回一个值 , 使用 *_UDest 接收返回值 ,
代码语言:javascript复制 for (; _UFirst != _ULast; _UFirst, (void) _UDest) {
*_UDest = _Func(*_UFirst);
}
之后 , 还要将该返回值 的 地址 作为参数 , 传递给 _Seek_wrapped 函数 ,
代码语言:javascript复制_Seek_wrapped(_Dest, _UDest);
这个 _Fn _Func 参数 执行后 , 必须有返回值 ;