- operator[] を非メンバーとしてオーバーロードすることはできません
- クラス定義で宣言されていないメンバー関数を定義することはできません
- std::pair のクラス定義を変更することはできません
非メンバーの実装は次のとおりです。
/// @return the nth element in the pair. n must be 0 or 1.
template <class T>
const T& pair_at(const std::pair<T, T>& p, unsigned int n)
{
assert(n == 0 || n == 1 && "Pair index must be 0 or 1!");
return n == 0 ? p.first: p.second;
}
/// @return the nth element in the pair. n must be 0 or 1.
template <class T>
T& pair_at(std::pair<T, T>& p, unsigned int index)
{
assert(index == 0 || index == 1 && "Pair index must be 0 or 1!");
return index == 0 ? p.first: p.second;
}
// usage:
pair<int, int> my_pair(1, 2);
for (int j=0; j < 2; ++j)
++pair_at(my_pair, j);
2 つのバージョンが必要であることに注意してください。1 つは読み取り専用ペア用で、もう 1 つは可変ペア用です。
非メンバー関数を自由に使用することを恐れないでください。Stroustrup 自身が言ったように、すべてをオブジェクトでモデル化したり、継承によってすべてを拡張したりする必要はありません。クラスを使用したい場合は、継承より合成を優先してください。
次のようなこともできます。
/// Applies func to p.first and p.second.
template <class T, class Func>
void for_each_pair(const std::pair<T, T>& p, Func func)
{
func(p.first);
func(p.second);
}
/// Applies func to p.first and p.second.
template <class T, class Func>
void for_each_pair(std::pair<T, T>& p, Func func)
{
func(p.first);
func(p.second);
}
// usage:
pair<int, int> my_pair(1, 2);
for_each_pair(my_pair, [&](int& x){
++x;
});
これは、C++11 ラムダを使用している場合に使用するのにそれほど扱いにくくはなく、範囲外にアクセスする可能性がないため、少なくとも少しは安全です。