使用迭代函数调用初始化std :: vector

Rom*_*lov 23 c++ iterator initialization stdvector c++11

在许多语言中,有一些生成器可以帮助初始化集合.在C++中,如果想要统一初始化向量,可以编写:

std::vector<int> vec(10, 42); // get 10 elements, each equals 42
Run Code Online (Sandbox Code Playgroud)

如果想要动态生成不同的值,该怎么办?例如,用10个随机值或从0到9的连续数字初始化它?这种语法很方便,但在C++ 11中不起作用:

int cnt = 0;
std::vector<int> vec(10, [&cnt]()->int { return cnt++;});
Run Code Online (Sandbox Code Playgroud)

有没有一种通过迭代函数调用初始化集合的好方法?我目前使用这种丑陋的模式(没有比循环更可读/更短):

std::vector<int> vec;
int cnt = 0;
std::generate_n(std::back_inserter(vec), 10, [&cnt]()->int { return cnt++;});
Run Code Online (Sandbox Code Playgroud)

有一件事会有所帮助,它可以解释缺少第一个构造函数.我可以设想一个迭代器,它接受一个函数和一些调用,以便构造函数

vector ( InputIterator first, InputIterator last);
Run Code Online (Sandbox Code Playgroud)

适用.但我在标准库中找不到这样的东西.我错过了吗?还有另一个原因导致第一个构造函数没有达到标准吗?

Xeo*_*Xeo 15

可悲的是,没有标准设施可以做到这一点.

对于您的具体示例,您可以counting_iterator像这样使用Boost.Iterator :

std::vector<int> v(boost::counting_iterator<int>(0),
    boost::counting_iterator<int>(10));
Run Code Online (Sandbox Code Playgroud)

或者甚至使用像这样的Boost.Range:

auto v(boost::copy_range<std::vector<int>>(boost::irange(0,10)));
Run Code Online (Sandbox Code Playgroud)

(copy_range基本上只是return std::vector<int>(begin(range), end(range))一个很好的方法,采用全范围构造来存在只支持带两个迭代器的范围构造的容器.)


现在,对于具有生成器功能(如std::rand)的通用情况,有function_input_iterator.递增时,它调用生成器并保存结果,然后在解除引用时返回结果.

#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 << " ";
}
Run Code Online (Sandbox Code Playgroud)

实例.

遗憾的是,由于function_input_iterator不使用Boost.ResultOf,您需要一个函数指针或一个嵌套result_type的函数对象类型.无论出于何种原因,兰巴达都没有.您可以将lambda传递给std::function(或boost::function)对象,该对象定义了该对象.这是一个例子std::function.人们只能希望Boost.Iterator有一天会使用Boost.ResultOf,这将使用decltypeif BOOST_RESULT_OF_USE_DECLTYPE定义.

  • 嗯.本地结构不能用作C++ 03中的模板参数,而在C++ 11中你有lambdas. (2认同)

Ker*_* SB 6

这个世界太大了,C++无法为所有东西提供解决方案.然而,C++并不想成为一个巨大的超市,为每一个可以想象的口味提供现成的饭菜.相反,它是一个小的,设备齐全的厨房中,的C++大厨,可以编造任何你想要的解决方案.

这是序列生成器的一个愚蠢而粗糙的例子:

#include <iterator>

struct sequence_iterator : std::iterator<std::input_iterator_tag, int>
{
    sequence_iterator() : singular(true) { }
    sequence_iterator(int a, int b) : singular(false) start(a), end(b) { }
    bool singular;
    int start;
    int end;

    int operator*() { return start; }
    void operator++() { ++start; }

    bool operator==(sequence_iterator const & rhs) const
    {
        return (start == end) == rhs.singular;
    }
    bool operator!=(sequence_iterator const & rhs) const
    {
        return !operator==(rhs);
    }
};
Run Code Online (Sandbox Code Playgroud)

现在你可以说:

std::vector<int> v(sequence_iterator(1,10), sequence_iterator());
Run Code Online (Sandbox Code Playgroud)

同样,你可以编写一个更通用的小工具,"调用给定的仿函数给定次数"等等(例如,通过模板化副本获取一个函数对象,并使用计数器作为重复计数器;并取消引用调用该仿函数).