我只是意识到标准并不能保证在std::transform
. 而且它不允许回调函数或仿函数有副作用。但同时std::for_each
实际上保证了订单。
一种猜测是变换可以使用不保证顺序的高性能算法,但是 O(N) 已经是最好的算法了。
那么为什么标准没有从应用回调函数顺序的角度transform
使行为具有?for_each
用户将从该保证中受益。
直接引用标准(最后复制):
您将从模板声明中std::transform<>
看到输入迭代器参数必须符合InputIterator
.
AnInputIterator
是 c++ 中限制性最强的迭代器概念之一。它不支持任何类型的随机访问。它只能前进。
因此,任何要求迭代器执行除被取消引用或提前之外的任何操作的 std::transform 实现都是格式错误的。请记住,通过指定InputIterator
,标准明确允许使用 a std::istream_iterator
(例如),并且std::transform
需要遵守其中的限制。它必须仅根据InputIterator
概念上可用的方法来编写。
因此,隐含地,此函数的实现必须按顺序访问元素(并因此按顺序转换值),因为不这样做会破坏接口中隐含的合同。
因此,该标准确实(隐式和悄悄地)保证std::transform
按顺序初始化其元素。编写一个格式良好的实现是std::transform
不可能的。
25.3.4 变换[alg.transform]
template<class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator
transform(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op);
template<class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation>
OutputIterator
transform(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperation binary_op);
i
1 效果:通过范围内的每个迭代器分配[result,result + (last1 - first1))
一个新的对应值等于op(*(first1 + (i - result))
orbinary_op(*(first1 + (i - result)), *(first2 + (i - result)))
。2 要求:op 和 binary_op 不得使迭代器或子范围无效,或修改范围 [first1,last1]、[first2,first2 + (last1 - first1)] 和 [result,result + (last1 - first1)] 中的元素。
3 返回:结果 + (last1 - first1)。
4 复杂性:恰好是 op 或 binary_op 的 last1 - first1 应用。
5 备注:一元变换的结果可能等于first,二元变换的结果可能等于first1或first2。
这种非限制性定义允许并行计算。一个实现可以选择使用多个线程来应用转换函数。另请参阅相关问题:STL 算法和并发编程
将其视为算法中的语义差异(即,它代表程序员的意图,而不仅仅是另一个工具)。与for_each
您声明您需要顺序扫描。你声明你只需要对transform
容器中的每个项目应用一个函数,但你并不关心它是如何完成的。
尽管有一些较早的答案,但我认为可以以并行方式实现 std::transform 。例如像这样:
1)按顺序获取所有输入。
2)迭代OutputIterator,初始化虚拟对象并保持对每个输出的引用。
3) 将输入与相应的输出迭代器分配给不同的线程,每个线程独立地进行转换。
像这样,迭代器只在允许的情况下递增。
正如 clcto 所指出的,另一个实现可以先执行步骤 1),然后为所有输出元素创建一个向量,然后使用给定的函数参数并行计算所有这些,然后将它们按顺序写入输出。