用迭代函数调用初始化std :: vector [英] Initializing std::vector with iterative function calls

查看:269
本文介绍了用迭代函数调用初始化std :: vector的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在许多语言中,有一些生成器可以帮助初始化集合。在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 << " ";
}

Live example。

很遗憾,由于 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆