用迭代函数调用初始化std :: vector [英] Initializing std::vector with iterative function calls
问题描述
在许多语言中,有一些生成器可以帮助初始化集合。在C ++中,如果想要均匀地初始化向量,可以写成:
In many languages, there are generators that help to initialize collections. In C++, if one wants to initialize a vector uniformly, one can write:
std::vector<int> vec(10, 42); // get 10 elements, each equals 42
如果想在飞行中生成不同的值,例如,用10个随机值或从0到9的连续数字初始化它?这种语法很方便,但在C ++ 11中不起作用:
What if one wants to generate different values on the fly? For example, initialize it with 10 random values, or consecutive numbers from 0 to 9? This syntax would be convenient, but it does not work in C++11:
int cnt = 0;
std::vector<int> vec(10, [&cnt]()->int { return cnt++;});
有没有很好的方法通过迭代函数调用来初始化集合?我目前使用这个丑陋的模式(不会比一个循环可读/短):
Is there a nice way to initialize a collection by iterative function calls? I currently use this ugly pattern (not much more readable/short than a loop):
std::vector<int> vec;
int cnt = 0;
std::generate_n(std::back_inserter(vec), 10, [&cnt]()->int { return cnt++;});
有一个事情可以帮助,这将解释缺少第一个构造函数。我可以想象一个迭代器,它接受一个函数和多个调用,所以构造函数
There is a thing that would help, and it would explain the lack of the first constructor. I can imagine an iterator that takes a function and number of calls, so that the constructor
vector ( InputIterator first, InputIterator last);
但我没有在标准库中找到这样的东西。我错过了吗?还有另一个原因,为什么第一个构造函数没有使它的标准?
would be applicable. But I did not find anything like this in the standard library. Did I miss it? Is there another reason why the first constructor did not make it to the standard?
推荐答案
可悲的是,没有标准的设施
Sadly, there is no standard facility to do this.
对于您的具体示例,您可以使用Boost.Iterator的 counting_iterator
:
For your specific example, you could use Boost.Iterator's counting_iterator
like this:
std::vector<int> v(boost::counting_iterator<int>(0),
boost::counting_iterator<int>(10));
或者甚至使用Boost.Range:
Or even with Boost.Range like this:
auto v(boost::copy_range<std::vector<int>>(boost::irange(0,10)));
( copy_range
基本上只是 return std :: vector< int>(begin(range),end(range))
,并且是一种很好的方法来采用全范围构造来存在只支持使用两个迭代器。)
(copy_range
will basically just return std::vector<int>(begin(range), end(range))
and is a great way to adopt full range construction to exisiting containers that only support range construction with two iterators.)
现在,对于具有生成函数的通用情况(如 std :: rand
),则有 function_input_iterator
。当递增时,它调用生成器并保存结果,然后在解除引用时返回。
Now, for the general purpose case with a generator function (like std::rand
), there is the function_input_iterator
. When incremented, it calls the generator and saves the result, which is then returned when dereferencing it.
#include <vector>
#include <iostream>
#include <cmath>
#include <boost/iterator/function_input_iterator.hpp>
int main(){
std::vector<int> v(boost::make_function_input_iterator(std::rand, 0),
boost::make_function_input_iterator(std::rand,10));
for(auto e : v)
std::cout << e << " ";
}
很遗憾,由于 function_input_iterator
不使用Boost.ResultOf需要具有嵌套 result_type
的函数指针或函数对象类型。 Lambdas,无论什么原因,没有。您可以将<$ em 传递给 std :: function
(或 boost :: function
)对象,它定义了它。 以下是一个使用 std :: function
的示例。我们只能希望Boost.Iterator有一天会使用Boost.ResultOf,这将使用 decltype
如果 BOOST_RESULT_OF_USE_DECLTYPE
是定义。
Sadly, since function_input_iterator
doesn't use Boost.ResultOf, you need a function pointer or a function object type that has a nested result_type
. Lambdas, for whatever reason, don't have that. You could pass the lambda to a std::function
(or boost::function
) object, which defines that. Here's an example with std::function
. One can only hope that Boost.Iterator will make use of Boost.ResultOf someday, which will use decltype
if BOOST_RESULT_OF_USE_DECLTYPE
is defined.
这篇关于用迭代函数调用初始化std :: vector的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!