C++0x の ranged-for ループには、配列を処理するための特別な例外があり (FDIS §6.5.4)、std::begin と end の 2 つの関数があり、配列を処理するため、または begin/end メソッドを選択するためにオーバーロードされます。これにより、一般的なシーケンスを受け入れる関数は、範囲指定された for ループの動作に一致するように記述できると思います。
template<class C>
void f(C &c) {
using std::begin;
using std::end;
do_something_with(begin(c), end(c));
}
C の名前空間に「より具体的な」begin/end がある場合は、ADL を介して選択されます。それ以外の場合、コードは std::begin/end に「デフォルト」設定されます。
ただし、範囲指定には特別な例外がある理由があります。ポインターを受け取る意味的に異なる begin/end を持つ名前空間で型の配列を渡す場合、std::begin/end の配列形式は選択されません。
namespace ns {
struct A {};
void begin(A*); // Does something completely different from std::begin.
}
void f_A() { // Imagine above f() called with an array of ns::A objects.
ns::A c[42];
using std::begin;
begin(c); // Selects ns::begin, not array form of std::begin!
}
これを回避するには、独自の begin/end ラッパー (内部で ADL を使用する) を作成し、std::begin または ADLized begin の代わりに明示的に呼び出すよりも良い解決策はありますか?
namespace my {
template<class T>
auto begin(T &c) // Also overload on T const &c, as std::begin does.
-> decltype(...) // See below.
{
using std::begin;
return begin(c);
}
template<class T, int N>
T* begin(T (&c)[N]) {
return c;
}
}
// my::end omitted, but it is analogous to my::begin.
template<class C>
void f(C &c) {
do_something_with(my::begin(c), my::end(c));
}
しかし、上記の省略記号で示されているように、my::begin! の書き方さえわかりません。その decltype に対して、ローカルの using 宣言と ADL によって選択される型を選択するにはどうすればよいですか?