Die ranged-for-Schleife von C++0x hat eine spezielle Ausnahme zur Behandlung von Arrays (FDIS §6.5.4), und es gibt zwei Funktionen, std::begin und end, die zur Behandlung von Arrays oder zur Auswahl von Anfangs-/Endmethoden überladen sind. Dies führt mich zu der Annahme, dass eine Funktion, die eine generische Sequenz akzeptiert, geschrieben werden könnte, um dem Verhalten einer Ranged-for-Schleife zu entsprechen:
template<class C>
void f(C &c) {
using std::begin;
using std::end;
do_something_with(begin(c), end(c));
}
Wenn es einen "spezifischeren" Anfang/Ende im Namensraum von C gibt, wird dieser über ADL ausgewählt, andernfalls wird standardmäßig std::begin/end verwendet.
Es gibt jedoch einen Grund dafür, dass für Fernabsatzgeschäfte diese besondere Ausnahme gilt. Wenn ein Array eines Typs in einem Namespace mit einem semantisch unterschiedlichen begin/end übergeben wird, der einen Zeiger annimmt, werden die Array-Formen von std::begin/end nicht ausgewählt:
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!
}
Um dies zu vermeiden, gibt es eine bessere Lösung als das Schreiben meiner eigenen Anfang/Ende-Wrapper (die ADL intern verwenden) und rufen Sie explizit anstelle von entweder std::begin oder ein ADLized beginnen?
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));
}
Aber wie die Ellipse oben zeigt, weiß ich nicht einmal, wie ich mein::begin schreiben soll! Wie kann ich für diesen decltype den Typ auswählen, der durch eine lokale using-Deklaration und ADL ausgewählt wird?