std::iota 非常有限

问题描述 投票:0回答:4

来自

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 中的一些东西。

c++ c++11
4个回答
38
投票

怎么样

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--;});

16
投票

但是该怎么办:

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


Range()

演示


9
投票

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; } };

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

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

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)) { ... } }



0
投票

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; }); }

而不是

iota(0) | stride(2)

这感觉更加笨拙和不必要的计算密集型(即使编译器也许可以从中产生更简单的东西)。

© www.soinside.com 2019 - 2024. All rights reserved.