累加器的函数对象应满足什么要求?

4
我在这里写了一个答案:https://stackoverflow.com/a/44481507/2642059,它使用accumulate
二元函数对象的签名必须像这样:Ret op(const auto& a, const auto& b),但是:

签名不需要有 const &

对于二元函数对象的要求是:

不能使任何迭代器失效,包括结束迭代器,也不能修改涉及到的任何元素

当被累加的对象本身是一个容器时,我对函数对象的要求不太清楚。例如,是否允许像这样做?
const auto range = { 0, 1, 2, 3 };
const auto Ret = accumulate(cbegin(range), cend(range), vector<int>(), [](auto& a, const auto& b){
    a.push_back(b);
    return a;
});

是的,我认识到这只是一份复制,我不是在寻求更好的解决方案,而是询问这个解决方案的有效性。


2
我相信它正在谈论应用于容器的迭代器。函数对象可以捕获正在迭代的容器并对其进行操作。考虑一个无序多集,你可以使用accumulate尝试将其中每个元素的数量“加倍”。这是不允许的,因为向哈希多集中添加元素可能会使迭代器失效。 - Nir Friedman
1
您可能会对以下相关提案感兴趣:https://isocpp.org/files/papers/p0616r0.pdf - Arne Vogel
1
@ArneVogel,我觉得你提出的建议非常棒!非常感谢你。我找了一个你的随机帖子并点了赞,结果发现了你关于 call_onceonce_flag 的帖子。这真是太好了,我以前从来没有听说过。现在我感觉需要把你所有的回答都仔细读一遍! - Jonathan Mee
@Drop 为什么你说“(而且可能不应该)”?我在构建字符串的代码中经常看到这个。我认为这是创建常量容器的常见解决方法,不是吗? - Jonathan Mee
1
@ArneVogel 我认为对于累积的吸引力主要源于它可以生成const容器,而其他方法则不能。我猜这就是Arne Vogel所提到的建议背后的真正动机。 - Jonathan Mee
显示剩余3条评论
1个回答

3
我认为工作草案比cppreference或其他文档更加明确:

在范围[first, last]binary_­op既不应修改元素,也不应使迭代器或子范围失效。

其中accumulate的声明如下:
template <class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init);

template <class InputIterator, class T, class BinaryOperation>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op);

因此,我认为你的例子是有效的,因为你没有影响范围[first, last]
另一方面,对于给定的范围,约束条件是完全有意义的,因为你用一对迭代器来定义它。例如,想象一下如果它们是一个向量的begin和end迭代器,在该向量的末尾你决定在binary_op中推入值会发生什么。一旦向量调整大小,accumulate将继续使用一对悬空指针。不好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接