【问题标题】:A post-increment operator that allows one to increment at a specified step一种后增量运算符,允许在指定的步长上进行增量
【发布时间】:2020-08-11 09:44:44
【问题描述】:

哪个更糟?

创建副本

#include <vector>
#include <algorithm>
template<class T>
std::vector<T> range(const T start, const T stop, const T step) {
    int leaps = ((stop-start)/step);
    std::vector<T> output(leaps > 0 ? leaps : -leaps);
    std::generate(output.begin(), output.end(), [i = start, step] () mutable {
        T num = i;
        i+=step;
        return num;
    });
    return output;
}

或重复(我假设一次计算)。

#include <vector>
#include <algorithm>
template<class T>
std::vector<T> range(const T start, const T stop, const T step) {
    int leaps = ((stop-start)/step);
    std::vector<T> output(leaps > 0 ? leaps : -leaps);
    std::generate(output.begin(), output.end(), [i = start-step, step] () mutable {return i+=step;});
    return output;
}

有没有办法避免两者?诸如后增量运算符之类的东西,其行为类似于 i++,但允许增量为 step

// Example
int main() {
    std::vector<double> check_range = range(-4.13, 2.13, 0.25);
    return 0;
}

预期

-4.13, -3.88, -3.63, -3.38, -3.13, -2.88, -2.63, -2.38, -2.13, -1.88, -1.63, -1.38, -1.13, -0.88, -0.63, -0.38, -0.13, 0.12, 0.37, 0.62, 0.87, 1.12, 1.37, 1.62, 1.87

【问题讨论】:

  • T 可以是浮点型还是整数型?
  • 是的,两者都可以。见编辑@Bob__
  • 你必须自己分析它。您的特定编译器可能能够以一种方式而不是另一种方式进行优化。它也可能取决于周围的环境,如建筑。你的意思是更糟糕的内存或性能或其他东西的使用?有很多因素,所以不能说一段代码比另一段差。
  • -4.13 的值无法在浮点变量中精确表示。重复添加0.25 的结果也不行。如果您期望 -4.13-3.88 等的确切值,您将会失望
  • “我想我正在寻找一个后增量运算符,它的行为类似于 i++,但允许增量为 step。” 这听起来像是 @ 的任务987654321@.

标签: c++ increment c++20


【解决方案1】:

在 C++20 中,我会懒惰地写它:

template <class T>
auto range(const T start, const T stop, const T step) {
    return views::iota(0)
         | views::transform([=](int i) -> T{
               return i * step + start;
           })
         | views::take_while([=](T cur){
               return cur < stop;
           });
}

如果你真的想要vector,你可以急切地评估它,但你可能不需要一次全部?


您也可以使用协程编写生成器(虽然 generator&lt;T&gt; 不在标准库中,需要像 cppcoro 一样使用):

template <class T>
generator<T> range(T start, const T stop, const T step) {
    for (; start < stop; start += stop) {
        co_yield start;
    }
}

同样,这是一个惰性范围,如果您真的需要,可以急切地将其评估为 vector

【讨论】:

    【解决方案2】:

    看看boost::irange。如果这不能满足您的需求,您可以进行一些算术运算。

    template<class T>
    auto range(const T start, const T stop, const T step) {
        int leaps = ((stop-start)/step);
        auto toT = [start, step](int i) { return start + (i * step); };
        return boost::irange(0, leaps > 0 ? leaps : -leaps) | boost::adaptors::transformed(toT);
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-02
      • 2012-10-17
      • 1970-01-01
      • 2015-08-20
      • 1970-01-01
      • 2015-10-21
      • 1970-01-01
      • 2010-10-14
      • 2015-10-16
      相关资源
      最近更新 更多