This SO question引发了关于std::generate
的讨论以及该标准所做的保证。特别是,您可以使用具有内部状态的函数对象并依赖generate(it1, it2, gen)
来调用gen()
,将结果存储在*it
中,再次调用gen()
,存储在{{1}中等等,或者它可以从后面开始,例如?
标准(n3337,§25.3.7/ 1)说明了这一点:
效果:第一个算法调用函数对象
*(it + 1)
,并通过gen
范围内的所有迭代器分配gen的返回值。第二个算法调用函数对象gen,如果[first,last)
为正,则通过[first,first + n)
范围内的所有迭代器分配gen的返回值,否则它什么都不做。
似乎没有保证排序,特别是因为其他段落具有更强的措辞,例如n
(效果:将std::for_each
应用于取消引用范围{{中的每个迭代器的结果1}},从第一个开始,然后继续f
。如果我们从字面上理解它,它只能保证从[first,last)
开始到last - 1
结束 - 不保证订购之间)。
但是: Microsoft's和Apache's C++ standard library都提供了文档页面上的示例,这些示例要求评估是连续的。 libc ++(在first
)和libstdc ++(在last
中)都以这种方式实现它。此外,如果没有此保证,您将失去algorithm
的许多潜在申请。
目前的措辞是否意味着顺序性?如果没有,这是委员会成员的疏忽还是故意的?
(我很清楚,没有多少人能够在不仅仅是推测或讨论的情况下为这个问题提供有见地的答案,但在我看来,根据SO指南,这并不会使这个问题“没有建设性”。 )
感谢@juanchopanza指出了这个问题,并引用了我关于bits/stl_algo.h
的段落。
答案 0 :(得分:7)
在LWG475的讨论中,std::for_each
与std::transform
进行了比较。注意到“transform
不保证其函数对象的调用顺序”。所以,是的,委员会意识到标准中缺乏顺序保证。
非顺序行为也没有相反的要求,因此Microsoft和Apache可以自由使用顺序评估。
答案 1 :(得分:5)
标准没有在算法上指定排序的任何地方,您应该假设实现可以利用它来实现并行性。文章n3408讨论了并行化的选项,并指向Thrust库,它既是标准算法的可用并行启用重新实现,也是未来标准化并行化的概念验证。算法
查看Thrust的generate
实现,只要迭代器类别是随机访问,它就会在并行循环中调用gen
。正如您所观察到的,这与标准一致,因此您不应该假设generate
始终是顺序的。 (例如,线程安全的std::rand
可以与generate
一起使用,并且不需要顺序调用。)
保证顺序调用的唯一算法是numeric
中的算法;如果您的代码依赖于顺序调用,则应使用iota
代替generate
。调整现有的生成器:
template<typename F> struct iota_adapter {
F f;
operator typename std::result_of<F()>::type() { return f(); }
void operator++() {}
};
template<typename F> iota_adapter<F> iota_adapt(F &&f) { return {f}; }
用作:
#include <numeric>
#include <iostream>
int main() {
int v[5], i = 0;
std::iota(std::begin(v), std::end(v), iota_adapt([&i]() { return ++i; }));
for (auto i: v) std::cout << i << '\n';
}