代码之家  ›  专栏  ›  技术社区  ›  malat

std::iota非常有限

  •  21
  • malat  · 技术社区  · 10 年前

    来自 Python 世界,我找到了功能 std::iota 非常有限。为什么接口被限制为不接受任何 UnaryFunction ?

    例如,我可以转换

    >>> x = range(0, 10)
    

    进入

    std::vector<int> x(10);
    std::iota(std::begin(x), std::end(x), 0);
    

    但如何做到:

    >>> x = range(0,20,2)
    

    甚至

    >>> x = range(10,0,-1)
    

    我知道编写一个这样的函数或使用Boost是微不足道的,但我认为C++委员会必须谨慎地选择这个设计。很明显,我在C++11中缺少了一些东西。

    3 回复  |  直到 10 年前
        1
  •  36
  •   Cris Luengo    4 年前

    怎么样 std::generate ?

    int n = -2;
    std::generate(x.begin(), x.end(), [&n]{ return n+=2; }); 
    int n = 10;
    std::generate(x.begin(), x.end(), [&n]{ return n--;});
    
        2
  •  16
  •   YSC    8 年前

    但如何做到:

    x = range(0,20,2)
    

    或者 std::generate() (参见其他答案),您可以提供自己的一元函数 std::iota() ,只需要打电话 operator++() :

    #include <iostream>
    #include <functional>
    #include <numeric>
    #include <vector>
    
    template<class T>
    struct IotaWrapper
    {
        typedef T type;
        typedef std::function<type(const type&)> IncrFunction;
    
        type value;
        IncrFunction incrFunction;
    
        IotaWrapper() = delete;
        IotaWrapper(const type& n, const IncrFunction& incrFunction) : value(n), incrFunction(incrFunction) {};
    
        operator type() { return value; }
        IotaWrapper& operator++() { value = incrFunction(value); return *this; }
    };
    
    int main()
    {
        IotaWrapper<int> n(0, [](const int& n){ return n+2; });
        std::vector<int> v(10);
        std::iota(v.begin(), v.end(), n);
    
        for (auto i : v)
            std::cout << i << ' ';
        std::cout << std::endl;
    }
    

    输出 : 0 2 4 6 8 10 12 14 16 18

    Demo


    下面是如何实现 Range() :

    struct Range
    {
        template<class Value, class Incr>
        std::vector<Value> operator()(const Value& first, const Value& last, const Incr& increment)
        {
            IotaWrapper<Value> iota(first, [=](const int& n){ return n+increment; });
            std::vector<Value> result((last - first) / increment);
            std::iota(result.begin(), result.end(), iota);
            return result;
        }
    };
    

    Demo

        3
  •  3
  •   Alexey Sokolov    5 年前

    使用C++20范围,您可以这样编写:

    static auto stepped_iota(int start, int step) {
      return std::ranges::views::iota(0) |
             std::ranges::views::transform([=](int x) { return x * step + start; });
    }
    
    void f() {
      for (int x : stepped_iota(0, 2)) { ... }
    }
    

    https://godbolt.org/z/3G49rs

    或者,如果您希望范围是有限的:

    static auto stepped_iota(int start, int end, int step) {
      return std::ranges::views::iota(0, (end - start + step - 1) / step) |
             std::ranges::views::transform([=](int x) { return x * step + start; });
    }