私はほんの少し前にこれを書いていることに気付きました:
template <long int T_begin, long int T_end>
class range_class {
public:
class iterator {
friend class range_class;
public:
long int operator *() const { return i_; }
const iterator &operator ++() { ++i_; return *this; }
iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }
bool operator ==(const iterator &other) const { return i_ == other.i_; }
bool operator !=(const iterator &other) const { return i_ != other.i_; }
protected:
iterator(long int start) : i_ (start) { }
private:
unsigned long i_;
};
iterator begin() const { return iterator(T_begin); }
iterator end() const { return iterator(T_end); }
};
template <long int T_begin, long int T_end>
const range_class<T_begin, T_end>
range()
{
return range_class<T_begin, T_end>();
}
これにより、次のような記述が可能になります。
for (auto i: range<0, 10>()) {
// stuff with i
}
今、私は自分が書いたものがおそらく最高のコードではないことを知っています。そして、もっと柔軟で便利な方法があるかもしれません。しかし、私には、このようなものが標準の一部にされるべきであるように思えます。
そうですか?ある範囲の整数に対するイテレータ用の新しいライブラリが追加されましたか、それとも計算されたスカラー値の一般的な範囲ですか?
C++標準ライブラリにはありませんが、 Boost.Rangeにはboost :: counting_range があり、これは確かに適格です。 boost :: irange を使用することもできます。これは、スコープにもう少し焦点を合わせています。
C++ 20の範囲ライブラリにより、view::iota(start, end)
を介してこれを行うことができます。
私の知る限り、C++ 11にはそのようなクラスはありません。
とにかく、私はあなたの実装を改善しようとしました。 advantageが表示されないため、非テンプレートにしました)作成中template。それどころか、大きな欠点が1つあります。コンパイル時にテンプレート引数を知る必要があるため、実行時に範囲を作成できないということです。
//your version
auto x = range<m,n>(); //m and n must be known at compile time
//my version
auto x = range(m,n); //m and n may be known at runtime as well!
コードは次のとおりです。
class range {
public:
class iterator {
friend class range;
public:
long int operator *() const { return i_; }
const iterator &operator ++() { ++i_; return *this; }
iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }
bool operator ==(const iterator &other) const { return i_ == other.i_; }
bool operator !=(const iterator &other) const { return i_ != other.i_; }
protected:
iterator(long int start) : i_ (start) { }
private:
unsigned long i_;
};
iterator begin() const { return begin_; }
iterator end() const { return end_; }
range(long int begin, long int end) : begin_(begin), end_(end) {}
private:
iterator begin_;
iterator end_;
};
テストコード:
int main() {
int m, n;
std::istringstream in("10 20");
if ( in >> m >> n ) //using in, because std::cin cannot be used at coliru.
{
if ( m > n ) std::swap(m,n);
for (auto i : range(m,n))
{
std::cout << i << " ";
}
}
else
std::cout <<"invalid input";
}
出力:
10 11 12 13 14 15 16 17 18 19
range
というライブラリを作成しましたが、ランタイム範囲であることを除いてまったく同じ目的で作成されました。私の場合のアイデアはPythonに由来します。私はコンパイル時のバージョンを検討しましたが、私の謙虚な意見では、コンパイル時のバージョンを入手する本当の利点はありません。ライブラリはbitbucketで見つけることができ、Boostライセンスの下にあります:Range。これは1ヘッダーライブラリで、C++ 03と互換性があり、C++ 11の範囲ベースのforループで魅力のように動作します:)
機能:
すべての機能を備えた真のランダムアクセスコンテナー!
範囲は辞書式に比較できます。
2つの関数exist
(ブール値を返す)、およびfind
(イテレータを返す)は、数値の存在を確認します。
ライブラリは [〜#〜] catch [〜#〜] を使用して単体テストされます。
基本的な使用例、標準コンテナの使用、標準アルゴリズムの使用、範囲ベースのforループの使用の例。
ここに1分の紹介があります 。最後に、この小さなライブラリに関する提案を歓迎します。
見つけた boost::irange
は、標準の整数ループよりもはるかに低速でした。そこで、プリプロセッサマクロを使用して、次のはるかに簡単なソリューションを決定しました。
#define RANGE(a, b) unsigned a=0; a<b; a++
その後、次のようにループできます。
for(RANGE(i, n)) {
// code here
}
この範囲は自動的にゼロから始まります。指定した番号から開始するように簡単に拡張できます。
これは私にとってうまく機能している簡単なフォームです。私のアプローチにはリスクがありますか?
r_iterator
は、long int
のように、可能な限り動作する型です。したがって、==
や++
などの多くの演算子は、単にlong int
にパススルーします。 operator long int
およびoperator long int &
変換を介して、基になるlong intを「公開」します。
#include <iostream>
using namespace std;
struct r_iterator {
long int value;
r_iterator(long int _v) : value(_v) {}
operator long int () const { return value; }
operator long int& () { return value; }
long int operator* () const { return value; }
};
template <long int _begin, long int _end>
struct range {
static r_iterator begin() {return _begin;}
static r_iterator end () {return _end;}
};
int main() {
for(auto i: range<0,10>()) { cout << i << endl; }
return 0;
}
(編集:-constの代わりにrange
のメソッドを静的にすることができます。)
これは少し遅いかもしれませんが、私はこの質問を見たばかりで、このクラスをしばらく使用しています:
#include <iostream>
#include <utility>
#include <stdexcept>
template<typename T, bool reverse = false> struct Range final {
struct Iterator final{
T value;
Iterator(const T & v) : value(v) {}
const Iterator & operator++() { reverse ? --value : ++value; return *this; }
bool operator!=(const Iterator & o) { return o.value != value; }
T operator*() const { return value; }
};
T begin_, end_;
Range(const T & b, const T & e) : begin_(b), end_(e) {
if(b > e) throw std::out_of_range("begin > end");
}
Iterator begin() const { return reverse ? end_ -1 : begin_; }
Iterator end() const { return reverse ? begin_ - 1: end_; }
Range() = delete;
Range(const Range &) = delete;
};
using UIntRange = Range<unsigned, false>;
using RUIntRange = Range<unsigned, true>;
使用法 :
int main() {
std::cout << "Reverse : ";
for(auto i : RUIntRange(0, 10)) std::cout << i << ' ';
std::cout << std::endl << "Normal : ";
for(auto i : UIntRange(0u, 10u)) std::cout << i << ' ';
std::cout << std::endl;
}
使ってみましたか
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function f);
ほとんどの場合、法案に適合します。
例えば。
template<class T> void printInt(T i) {cout<<i<<endl;}
void test()
{
int arr[] = {1,5,7};
vector v(arr,arr+3);
for_each(v.begin(),v.end(),printInt);
}
PrintIntは、C++ 0xではOFCをラムダに置き換えることができることに注意してください。また、この使用法のもう1つの小さなバリエーションは(random_iteratorに対して厳密に)
for_each(v.begin()+5,v.begin()+10,printInt);
Fwdのみのイテレーター
for_each(advance(v.begin(),5),advance(v.begin(),10),printInt);