构造时,用整数序列填充向量

Populate vector with integer sequence, on construction

本文关键字:填充 向量 整数      更新时间:2023-10-16

我正试图在向量的构造上用整数序列填充vector(或其他容器)(与此问题相反)。以下代码实现了我的意图,使用vector的range构造函数和Boost的counting_range:

#include <iostream>
#include <vector>
#include <boost/range/counting_range.hpp>
using namespace std;
int main () {
vector<int> test_vector(boost::counting_range(2,10).begin(),boost::counting_range(2,10).end());
for (auto i : test_vector)  cout << i << endl;
}

问题:

  1. 我可以消除counting_range(2,10).begin()counting_range(2,10).end()中的重复吗?目前,我正在两次指定(2,10)的范围。
  2. 这可以在没有Boost的情况下完成吗?只使用普通的C++11或C++0x编辑:还是C++14

编辑:

  • 我想实例化向量并在一条语句中指定范围。例如,在Python中,我可以编写test_vector=range(2,9)。在R/Octave/Matlab中可以编写test_vector=2:9test_vector=seq(2,9,1)。在这方面,我对以上内容感到满意。
  • 我在上面使用了"2"answers"10",但范围的边界可以是动态的,任何整数aba的范围内;b。因此,像{2,3,…,9}这样的初始化列表是不可取的,因为它必须在编译时指定。
  • 我上面使用的方法也可以用于在一条语句中初始化其他容器;以下方法也适用:unordered_set test_set(boost::counting_range(2,10).begin(),boost::counting_range(2,10).end());

    如果任何解决方案也是"独立于容器"的,那就太好了。

  • 我同意@davidrodriguez-dribeas的观点,即我们可以通过初始化构造函数体中的向量来坚持Meyer的项;它没有必要在构造函数的初始化列表中完成。因此,我删除了下面的这一部分

动机

:我想这么做是因为我想遵守我代码中其他地方的有效C++中Meyer的第4项("确保对象在使用之前已经初始化。")。例如:

class my_class {
public:
my_class()
:vec(boost::counting_range(2,10).begin(),boost::counting_range(2,10).end()) {}
vector<int> vec;
};

不要过度。简单的做法是默认初始化向量,保留并从范围初始化。

确保在使用对象之前对其进行初始化

这并不意味着必须在初始化列表中完全初始化成员,而不是在构造函数完成时必须完全初始化my_class对象。

除此之外,为了方便起见,在香草C++中可以做一些不同的事情来处理这一问题,比如创建一个辅助函数并按值返回向量:

std::vector<int> create_vector() {
std::vector<int> v;
// ...
return v;
}

但我不会使用这个(或任何其他替代方案)来初始化成员,只有当需要时(向量是const可能是充分的借口:)

您可以使用由范围分隔的序列来构造std::vector<T>。您只需要一个合适的输入迭代器来初始化序列,然后就可以定义迭代器,这样您就可以为end使用默认构造的迭代器了,例如:

class counter: public std::iterator<std::input_iterator_tag, int> {
int current;
int end;
public:
counter(): current(), end() {}
counter(int c, int e): current(c), end(e) {}
int const& operator*() const { return this->current; }
counter& operator++() { ++current; return *this; }
counter  operator++(int) { counter rc(*this); ++current; return rc; }
bool operator== (counter const& other) const {
return (end - current) == (other.end - other.current);
}
bool operator!= (counter const& other) const { return !(*this == other); }
};
std::vector<int> v(counter(2, 10), counter());

Boost方法是使用boost::copy_range:

auto vec = boost::copy_range<std::vector<int>>(boost::irange(0, 10));

boost::copy_range是一个函数模板,它返回其第一个模板参数类型的对象:

template< typename SeqT, typename Range >
inline SeqT copy_range( const Range& r )
{
return SeqT( boost::begin( r ), boost::end( r ) );
}

您必须将返回类型指定为模板参数,这可能违反DRY,但可以避免使用AAA样式,如我上面的示例所示,或者在类初始值设定项中使用decltype:

class S {
public:
S() : vec(boost::copy_range<decltype(vec)>(boost::irange(0, 10)) {}
private:
const std::vector<int> vec;
};

这让从未让任何人失望过,而且它完全是普通的,甚至可以与C++03一起使用(如果你像我一样后台端口beginend;如果不是,只使用编译时数组大小):

int inits[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> test_vector ( begin(inits), end(inits) );

如果序列是另一种序列,您只需要调整初始化数组,或者使用生成器对象,然后bam!它完成了。

至于避免(1)中的重复,如果以下内容有任何问题,会有什么问题?

const boost::counting_range init_range(2,10);
vector<int> test_vector( begin(init_range), end(init_range) );

您可以直接使用boost::counting_迭代器来初始化您的序列,而不是创建boost::counting_range。

#include <iostream>
#include <vector>
#include <boost/iterator/counting_iterator.hpp>
int main () 
{
std::vector<int> aVec(boost::counting_iterator<int>(0), boost::counting_iterator<int>(10));
for (int i : aVec)
{
std::cout << i << std::endl;
}
return 0;
}