私自身、私が取り組んでいるプロジェクトでは、含まれる値が決して負になることはありませんが、ほとんどの場合、符号付き整数が最良の選択であると確信しています。(特に 0 から 20 の間の値しか保持できない整数の場合、ループの単純な逆、バグの可能性が少なくなります。)
これがうまくいかない場所の大部分は、std::vector の単純な繰り返しです。多くの場合、これは過去には配列でしたが、後で std::vector に変更されました。したがって、これらのループは一般的に次のようになります。
for (int i = 0; i < someVector.size(); ++i) { /* do stuff */ }
このパターンは非常に頻繁に使用されるため、符号付き型と符号なし型のこの比較に関するコンパイラ警告スパムの量によって、より有用な警告が隠される傾向があります。INT_MAX 要素を超えるベクトルは絶対にないことに注意してください。これまで、コンパイラの警告を修正するために 2 つの方法を使用していたことに注意してください。
for (unsigned i = 0; i < someVector.size(); ++i) { /*do stuff*/ }
これは通常は機能しますが、ループに「if (i-1 >= 0) ...」などのコードが含まれていると、黙って中断する可能性があります。
for (int i = 0; i < static_cast<int>(someVector.size()); ++i) { /*do stuff*/ }
この変更には副作用はありませんが、ループが読みにくくなります。(そして、それはより多くのタイピングです。)
そこで、次のアイデアを思いつきました。
template <typename T> struct vector : public std::vector<T>
{
typedef std::vector<T> base;
int size() const { return base::size(); }
int max_size() const { return base::max_size(); }
int capacity() const { return base::capacity(); }
vector() : base() {}
vector(int n) : base(n) {}
vector(int n, const T& t) : base(n, t) {}
vector(const base& other) : base(other) {}
};
template <typename Key, typename Data> struct map : public std::map<Key, Data>
{
typedef std::map<Key, Data> base;
typedef typename base::key_compare key_compare;
int size() const { return base::size(); }
int max_size() const { return base::max_size(); }
int erase(const Key& k) { return base::erase(k); }
int count(const Key& k) { return base::count(k); }
map() : base() {}
map(const key_compare& comp) : base(comp) {}
template <class InputIterator> map(InputIterator f, InputIterator l) : base(f, l) {}
template <class InputIterator> map(InputIterator f, InputIterator l, const key_compare& comp) : base(f, l, comp) {}
map(const base& other) : base(other) {}
};
// TODO: similar code for other container types
表示されるのは、基本的に、size_type をオーバーライドして「int」のみを返すメソッドを持つ STL クラスです。これらは継承されないため、コンストラクターが必要です。
既存のコードベースでこのようなソリューションが見られるとしたら、開発者としてこれをどう思いますか?
「うわあ、彼らは STL を再定義している、なんと巨大な WTF だ!」と思いますか?それとも、これはバグを防ぎ、読みやすさを向上させるための素晴らしいシンプルなソリューションだと思いますか? それとも、これらすべてのループを std::vector<>::iterator を使用するように変更するのに (半日) ほど費やしたことを知りたいですか?
(特に、この解決策が生データ (例: unsigned char) とビット マスク以外での unsigned 型の使用の禁止と組み合わされた場合。)