在C ++中,我们具有std::fill
或std::fill_n
之类的函数,这些函数是方便的单行方式,将指针数组,向量,std::array
和其他容器填充为值。一些容器还具有自己的fill
方法,以允许以恒定值进行填充。还有函数std::generate{_n}
和std::iota
,前者允许使用生成器函数填充元素,而后者则用索引填充范围。
我正在寻找的是一种类似的解决方案-最好是一种单线解决方案,并在标准库中定义-允许使用索引的某些功能填充容器。例如,这将是数组的解决方案:
std::array<int, 100> arr;
for (std::size_t i = 0; i < 100; i++)
arr[i] = f(i);
其中f(std::size_t i)
是索引的某些功能。
是否有执行此操作的集成方法?
您可以使用有状态的lambda:
std::array<int, 100> arr;
std::generate(arr.begin(), arr.end(), [i = std::size_t(0)]() mutable {return f(i++);});
但是我认为这使代码变得比所需的复杂。使用普通循环可能是最好的选择。
如果您始终遍历整个数组,则甚至不必使用任何stl函数,只需使用范围循环:
std::array<int, 100> arr;
int idx = 0;
for (auto& item : array)
item = f(idx++);
另一种选择是使用for_each
(如果将来您想填充数组[[仅部分,这可能会更有用)]
#include <algorithm>
std::array<int, 100> arr;
int idx = 0;
std::for_each(begin(arr), end(arr), [&idx](int &n){ n = f(idx++); });
不幸的是,在两种情况下,您都必须具有单独的索引变量(这里:idx
)
STL-like函数模板apply_idx_func()
:
template<typename FwdItor, typename F>
void apply_idx_func(FwdItor first, FwdItor last, F f) {
for (size_t idx = 0; first != last; ++first, ++idx)
*first = f(idx);
}
例如:
auto main() -> int { std::array<int, 10> arr; // just adds 100 to the index auto func = [](size_t idx) -> int { return 100 + idx; }; apply_idx_func(std::begin(arr), std::end(arr), func); for (auto elem: arr) std::cout << elem << ' '; std::cout << '\n'; }
输出为:
100 101 102 103 104 105 106 107 108 109
#include <algorithm>
size_t i = 0;
std::generate_n(arr.begin(),arr.size(),[&i](){return f(i++);});
或者可能分两个步骤:
#include <numeric> std::iota(arr.begin(),arr.end(),0); std::transform(arr.begin(),arr.end(),f);
借助boost,我们可以一步完成此操作:
std::transform( arr.begin(), arr.end(), boost::irange(0,arr.size()), [](const auto& val,const auto& index){return f(index);} );
https://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/ranges/irange.html
std::ranges::transform(std::views::iota{1, arr.size()+1}, arr, f);
或者,如果只需要生成值的序列,只需使用]创建它们的范围
auto const values = std::views::iota{1, arr.size()+1} | std::views::transform(f);
除非您拥有C ++ 20编译器,否则可以使用范围库之一,例如在Boost或Eric Nieblers ranges-v3