Frage

Welchen Teil der C ++ - Spezifikation beschränkt sich auf die Argument -abhängige Suche in der Suche nach Funktionsvorlagen in der Menge der zugehörigen Namespaces? Mit anderen Worten, warum ruft der letzte Anruf ein? main unten nicht kompilieren?

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
    void non_template(foo const&) {}
}

int main() {
    ns::foo f;
    non_template(f); // This is fine.
    frob<0>(f); // This is not.
}
War es hilfreich?

Lösung

Dieser Teil erklärt es:

C ++ Standard 03 14.8.1.6:

Hinweis: Für einfache Funktionsnamen gilt die Argument -abhängige Suche (3.4.2) auch dann, wenn der Funktionsname im Rahmen des Aufrufs nicht sichtbar ist. Dies liegt daran, dass der Anruf still die syntaktische Form eines Funktionsaufrufs (3.4.1) hat. Wenn jedoch eine Funktionsvorlage mit expliziten Vorlagenargumenten verwendet wird, hat der Aufruf nicht das richtige syntaktische Formular, es sei denn, es gibt eine Funktionsvorlage, bei der dieser Name am Punkt des Aufrufs sichtbar ist. Wenn kein solcher Name sichtbar ist, ist der Anruf nicht syntaktisch gut geformt und es gilt nicht argumentabhängig. Wenn ein solcher Name sichtbar ist, gilt die argumentabhängige Suche und zusätzliche Funktionsvorlagen finden Sie in anderen Namensspitzen.

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);    //ill-formed: not a function call
  A::f<3>(b); //well-formed
  C::f<3>(b); //ill-formed; argument dependent lookup
              // applies only to unqualified names
  using C::f;
  f<3>(b);    //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}

Andere Tipps

Ich möchte eine leicht akzeptierte Antwort verfeinern. In der OP -Frage ist nicht klar, aber der wichtige Teil des Standards (zitiert von Kornel) ist dies (Hervorhebung Mine):

Aber wenn eine Funktionsvorlage mit Explizite Vorlagenargumente wird verwendet, der Anruf hat nicht die richtige syntaktische Form

Was verboten ist, stützt sich also auf ADL und verwendet explizite Vorlagenargumente. Die Verwendung von Argumenten für nicht-type-Vorlagen erfordert leider die Verwendung explizite Argumente (es sei denn, sie haben Standardwerte).

Im Folgenden finden Sie einen Beispielcode .:::

live

#include <string>
#include <utility>

namespace C {
  struct B { };
  template<class T> void f(T t){}
}

void g(C::B b) {
  f(b);           // OK
  //f<C::B>(b);   // ill-formed: not a function call, but only 
                  //  because explicit template argument were used

  std::string s;
  move(s);                      // OK
  //move<std::string&>(s);      // Error, again because 
                                //  explicit template argument were used
  std::move<std::string&>(s);   // Ok
}

int main()
{
 C::B b;
 g(b);
}

Seit C ++ 20 arbeitet ADL auch gut mit explizite Funktionsvorlage. Hier ist der Vorschlag:P0846R0: ADL- und Funktionsvorlagen, die nicht sichtbar sind:

Anstatt dass der Benutzer das Schlüsselwort der Vorlage verwenden kann, wurde eine Überarbeitung der Suchregeln vorgeschlagen, so dass ein Name, für den ein normales Suchanlagen entweder kein Ergebnis erbringt oder eine oder mehrere Funktionen findet und von AA "<" folgt, als Wenn ein Funktionsvorlagenname gefunden worden wäre und ADL ausführen würde.

Derzeit hat nur GCC 9 diese Funktion implementiert, sodass Ihr Beispiel kompilieren kann.

live demo.

Bearbeiten: Nein, das ist nicht richtig. Sehen @Kornels Antwort.


Ich bin mir nicht ganz sicher, aber nachdem ich Strousstrups "The C ++ Programmiersprache" konsultiert habe, denke ich, dass Anhang C Abschnitt 13.8.4 könnte die Ursache sein.

Seit frob ist eine Vorlage, für die man sie möglicherweise spezialisiert hat? i=0 An einem Punkt, nachdem Sie es angerufen haben. Dies bedeutet, dass die Implementierung zwei mögliche Möglichkeiten zur Auswahl dessen erhalten würde, welche frob Um so zu rufen, wie es erscheint, kann es es am Zeitpunkt der Instanziierung wählen oder Am Ende der Verarbeitung der Übersetzungseinheit.

Ich denke, das Problem ist, dass Sie es tun könnten

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
}

int main() {
    ns::foo f;
    frob<0>(f);
    return 0;
}

namespace ns {
    template<> void frob< 0 >(foo const&) { /* Do something different*/ }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top