【问题标题】:Why does ranges::accumulate not pass init as std::move(init) when invoke?为什么 range::accumulate 在调用时不将 init 作为 std::move(init) 传递?
【发布时间】:2018-04-24 11:10:11
【问题描述】:

截至 2018 年 3 月 17 日提交 d5e9afc 的 accumulate.hpp

当传递一个范围时,init 会像这样得到一次std::move

        T operator()(Rng && rng, T init, Op op = Op{}, P proj = P{}) const
        {
            return (*this)(begin(rng), end(rng), std::move(init), std::move(op),
                std::move(proj));
        }

上面的代码会调用这个:

        T operator()(I begin, S end, T init, Op op = Op{}, P proj = P{}) const
        {
            for(; begin != end; ++begin)
                init = invoke(op, init, invoke(proj, *begin)); // why do we need this another copy of init?
            return init;
        }

我想知道为什么我们在调用调用之前需要另一个 init 副本?

这个初始化必须以任何方式被覆盖,对吧?那么为什么一开始就不能把它撕掉呢?

                init = invoke(op, std::move(init), invoke(proj, *begin));

【问题讨论】:

  • invoke 是否按值接受?
  • @StoryTeller 为什么要禁止将东西作为参数移动?
  • 我的猜测是 init 旨在成为原始类型,因此按值传递可能会更有效。
  • @Galik 移动非原始税额外周期?或者图书馆试图鼓励使用init 作为一个前言?还是两者兼有?

标签: c++ accumulate range-v3


【解决方案1】:

这段代码试图避免假设它看起来是 C++17。 std::move-ing init 可能会修改它(这就是移动语义的用途,归根结底)。这给我们留下了这样的东西:

init = /* An expression that maybe modifies init */;

这将导致undefined behavior prior to C++17。 range-v3 也将自己宣传为 C++11 和 C++14 的库。

【讨论】:

  • 如果仅此而已,那你觉得他们会不会加C++17+宏这个动作?
  • @sandthorn - IDK,我不在乎他们的想法 :) 这是一个开源项目,如果您发现有改进的空间,请向他们发送拉取请求。
  • undefined behavior prior to C++17 您介意指出哪个 C++14 标准部分明确声明了未定义吗?
  • @sandthorn - 在 SO 上已经提到过。见here
  • 经过一番阅读,我发现std::accumulate 需要CopyConstructible 来自init,所以必须保持原样,直到std 自己改变的那一天。此外,我猜 range-v3 会向<numeric> 投诉。但是,std::reduce 现在确实需要初始化 MoveConstructible!!。不过,似乎还没有实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 1970-01-01
  • 2014-02-16
  • 2022-11-02
相关资源
最近更新 更多