質問
どのように思を固定して傾きを解消しこのコードについて教えてください。
template <typename T> void closed_range(T begin, T end)
{
for (T i = begin; i <= end; ++i) {
// do something
}
}
Tは制限され整数タイプは、より広いなどの種類できる署名または符号なし
begin
可numeric_limits<T>::min()
end
可numeric_limits<T>::max()
(この場合は++i
まオーバーフロー上のコード)
私は、なかなっています。
解決
たぶん、
template <typename T> void closed_range(T begin, const T end)
if (begin <= end) {
do {
// do something
} while (begin != end && (++begin, true));
}
}
呪い、私の最初の試みは間違っていた、と上記の修正は、私が期待したいほどかわいいではありません。いかがます:
template <typename T> bool advance(T &value) { ++value; return true; }
template <typename T> void closed_range(T first, const T last)
if (first <= last) {
do {
// do something
} while (first != last && advance(first));
}
}
std::advance
は、2つのパラメータを取りますので、Tは、整数型でない場合でもstd::advance
とは曖昧さはありません。何らかの理由であなたがそれらの閉じた範囲を望んでいたのであれば、テンプレートはまた、例えば、ランダムアクセスイテレータで動作します。
またはどのように集合論のビットはどうですか?あなただけの閉じた範囲にわたり一つのループを書いている場合は明らかにこれは、大規模なやり過ぎですが、それはあなたが多くのことをやりたい何かあれば、それは権利についてループコードになります。
:あなたは確かendof
への呼び出しが掲揚されていることを確認したい場合があります、本当にタイトなループで:効率わかりません
#include <limits>
#include <iostream>
template <typename T>
struct omega {
T val;
bool isInfinite;
operator T() { return val; }
explicit omega(const T &v) : val(v), isInfinite(false) { }
omega &operator++() {
(val == std::numeric_limits<T>::max()) ? isInfinite = true : ++val;
return *this;
}
};
template <typename T>
bool operator==(const omega<T> &lhs, const omega<T> &rhs) {
if (lhs.isInfinite) return rhs.isInfinite;
return (!rhs.isInfinite) && lhs.val == rhs.val;
}
template <typename T>
bool operator!=(const omega<T> &lhs, const omega<T> &rhs) {
return !(lhs == rhs);
}
template <typename T>
omega<T> endof(T val) {
omega<T> e(val);
return ++e;
}
template <typename T>
void closed_range(T first, T last) {
for (omega<T> i(first); i != endof(last); ++i) {
// do something
std::cout << i << "\n";
}
}
int main() {
closed_range((short)32765, std::numeric_limits<short>::max());
closed_range((unsigned short)65533, std::numeric_limits<unsigned short>::max());
closed_range(1, 0);
}
出力:
32765
32766
32767
65533
65534
65535
omega<T>
オブジェクト上の他の演算子を使って少し注意が必要です。私はデモのために絶対的な最小値を実装しました、とomega<T>
は暗黙のうちにT
に変換するので、あなたが潜在的にオメガオブジェクトの「infinitenessを」捨てる式を書くことができることがわかります。あなたは、算術演算子の完全なセットを宣言(必ずしも定義する)ことによって、その問題を解決できました。またはisInfiniteが真である場合、変換中に例外をスローすることにより、あるいは単にコンストラクタは、明示的であるので、あなたが誤って、バックオメガに結果を変換することができないことを理由に、それについて心配しないでください。しかし、例えば、omega<int>(2) < endof(2)
は本当ですが、omega<int>(INT_MAX) < endof(INT_MAX)
はfalseです。
他のヒント
私のテイクます:
// Make sure we have at least one iteration
if (begin <= end)
{
for (T i = begin; ; ++i)
{
// do something
// Check at the end *before* incrementing so this won't
// be affected by overflow
if (i == end)
break;
}
}
この作品で、かなり明確である:
T i = begin;
do {
...
}
while (i++ < end);
あなたがbegin >= end
の特殊なケースをキャッチしたい場合は、あなたはスティーブ・ジェソップのソリューションのように別のif
を追加する必要があります。
template <typename T, typename F>
void closed_range(T begin, T end, F functionToPerform)
{
for (T i = begin; i != end; ++i) {
functionToPerform(i);
}
functionToPerform(end);
}
EDIT:より密接OPと一致するものを作り直しました。
。#include <iostream>
using namespace std;
template<typename T> void closed_range(T begin, T end)
{
for( bool cont = (begin <= end); cont; )
{
// do something
cout << begin << ", ";
if( begin == end )
cont = false;
else
++begin;
}
// test - this should return the last element
cout << " -- " << begin;
}
int main()
{
closed_range(10, 20);
return 0;
}
出力されます:
10、11、12、13、14、15、16、17、18、 19、20 - 20