11 Stimmen

Generisch beginnend, plus decltype unter Berücksichtigung der lokalen using-Deklaration

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?

4voto

Luc Danton Punkte 34153

Ich bin bei der Verwendung von Tupeln auf die gleiche Situation gestoßen:

template<typename Tuple>
auto f(Tuple&& tuple)
-> /* ??? */
{
    using std::get;
    return get<Idx>(tuple);
}

die sowohl die std::tuple y boost::tuple und akzeptiert sowohl lWerte als auch rWerte im Gegensatz zu template<typename... Types> auto f(std::tuple<Types...>& tuple) -> /* ??? */ .

Dieser spezielle Fall wurde mit einer Traits-Klasse gelöst, die in der Tat vom Standard vorgesehen ist: std::tuple_element . Wie bei Traits-Klassen üblich, besteht die Idee darin, dass tuple ist ein Protokoll, und alles, was ihm entsprechen will, wird eine Spezialisierung für z.B. tuple_element . In meinem Fall war die Lösung also bereits vorhanden.

In Ihrem Fall, wenn Sie eine Bibliothek schreiben würden, würde ich empfehlen, eine solche Traits-Klasse zu schreiben (und zu dokumentieren). Bei Anwendungscode oder anderen Situationen bin ich mir da nicht so sicher.

1voto

Jan Hudec Punkte 69126

Sie können die Arrays selbst mit Sonderzeichen versehen. Der Typ eines Arrays ist (und muss sein, damit begin/end funktioniert) ElementType (&)[Size] Wenn Sie also die Funktion überladen wie:

template<class C, size_t S>
void f(C (&c)[S]) {
  do_something_with(std::begin(c), std::end(c));
}

sollte sie sich speziell wie die for-Schleife verhalten.

Nebenbei bemerkt: Sie brauchen keine std::begin y std::end dann sind sie trivial:

template<class C, size_t S>
void f(C (&c)[S]) {
  do_something_with(c, c + S);
}

(kann ein Cast benötigen; ich habe es eigentlich nur mit Dingen verwendet, die Zeiger verlangten, keine Iteratoren).

Eine weitere Randnotiz, begin y end Funktionen, die auf Zeiger hinweisen, sind ziemlich dumm. Wenn das Objekt, auf das gezeigt wird, eine Sammlung ist, sollten sie wahrscheinlich stattdessen eine Referenz nehmen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X