C ++中的整数范围 - 如果标准不存在,我该怎么办?

时间:2016-03-11 10:22:07

标签: c++ c++11 boost c++17

我知道C ++重量级人物正致力于将范围纳入语言,或者至少是标准库:

公平地说 - 我还没有通读官方建议。我只是一个想要使用简单范围功能的谦虚的C ++程序员。我应该做什么今天而不是在C ++ 17之后使用,比方说,带有步幅的简单整数范围?当然,当我开始实际使用范围时,我的要求可能会扩大,但我仍然没有追求更高级的东西以及各种各样的角落情况。我想。

在限制性更强的一面,由于兼容性需求(CUDA),我正在处理一个有点旧的环境,因此我需要使用GCC 4.9.3及其相应的标准库版本,以及我可以使用的东西GPU代码(不一定是相同的库/标题,但希望是相同的)。

那么,我应该推出自己的有限功能整数范围类型,等待手续解决 - 或者我应该选择更重量级的替代方案之一(Niebler' Ranges v3&# 34;,Boost irange等)?

1 个答案:

答案 0 :(得分:3)

写一个简单的"索引" - 存储类型T并通过副本返回类型O=T的输入迭代器很容易。

我称之为index的是一个迭代器,它包含支持进度和比较(包括其他迭代器和类似整数的东西)的东西,并在取消引用时返回包含对象的副本。生成范围超过迭代器到范围也很有用。

template<class T, class O=T>
struct index_t:
  std::iterator<
    std::input_iterator_tag,
    O, std::ptrdiff_t, O*, O
  >
{
  T t;
  explicit index_t(T&& tin):t(std::move(tin)){}
  explicit index_t(T const& tin):t(tin){}
  index_t()=default;
  index_t(index_t&&)=default;
  index_t(index_t const&)=default;
  index_t& operator=(index_t&&)=default;
  index_t& operator=(index_t const&)=default;

  O operator*()const{ return t; }
  O operator*(){ return t; }
  O const* operator->()const{ return &t; }
  O* operator->(){ return &t; }

  index_t& operator++(){ ++t; return *this; }
  index_t operator++(int){ auto r = *this; ++*this; return r; }

  friend bool operator==(index_t const& lhs, index_t const& rhs) {
    return lhs.t == rhs.t;
  }
  friend bool operator!=(index_t const& lhs, index_t const& rhs) { return !(lhs==rhs); }
};
template<class Scalar>
index_t<Scalar> index_to( Scalar s ) {
  return index_t<Scalar>(std::move(s));
}
或某些人。 index_t<int>是一个无步幅的整数迭代器。

如果我们想要步幅:

template<class T, class D=std::size_t>
struct strided {
  T t;
  D stride;
  strided( T tin, D sin ):t(std::move(tin)), stride(std::move(sin)) {}

  strided& operator++(){ t+=stride; return *this; }
  strided operator++(int){ auto r = *this; ++*this; return r; }
  operator T()&&{return std::move(t);}
  operator T() const &{return t;}

  friend bool operator==(strided const& lhs, strided const& rhs){
    return lhs.t == rhs.t;
  }
  friend bool operator!=(strided const& lhs, strided const& rhs) { return !(lhs==rhs); }
};

template<class T, class D=std::size_t>
using strided_index_t = index_t<strided<T,D>, T>;

现在你只需要写range_t<Iterator>(开始,结束,空,前,后,构造函数)。

template<class T>
strided_index_t<T> strided_index_to( T t, std::size_t d ) {
  return strided_index_t<T>( {std::move(t), d} );
}
template<class It>
struct range_t {
  It b,e;
  using element_type = decltype( *std::declval<It>() );
  It begin() const { return b; }
  It end() const { return e; }
  bool empty() const { return begin()==end(); }
  element_type front() const { return *begin(); }
  element_type back() const { return *std::prev(end()); }
};
template<class It>
range_t<It> range(It b, It e){
  return {std::move(b), std::move(e)};
}

现在我们可以制作索引范围:

template<class Scalar>
range_t<index_t<Scalar>> index_range( Scalar b, Scalar e ) {
  return range( index_to(std::move(b)), index_to(std::move(e)) );
}
template<class Scalar>
range_t<strided_index_t<Scalar>> strided_index_range( Scalar b, Scalar e, std::size_t d ) {
  return range( strided_index_to(std::move(b), d), strided_index_to(std::move(e), d) );
}

现在我们测试:

for (int i : index_range(0, 10))
  std::cout << i << '\n';
for (int i : strided_index_range(0, 10, 2))
  std::cout << i << '\n';

boost和其他基于范围的库中也存在类似的对象。

Live example

顺便说一下,

for( auto it : index_to( begin(vec), end(vec) ) )

以基于范围的方式迭代vec的迭代器。写

for( auto it : iterators_into(vec) )

也很容易。