Frage

Vor einiger Zeit wurde ich durch das folgende Verhalten von Code verwirrt, wenn ich ein is_callable<F, Args...> Merkmal schreiben wollte. Überladungsauflösung wird Funktionen nicht aufrufen Argumente nicht-const ref zu akzeptieren, nicht wahr? Warum nicht, es in den folgenden ablehnen, weil der Konstruktor ein Test& will? Ich erwartete es f(int) nehmen!

struct Test {
  Test() { }

  // I want Test not be copyable from rvalues!
  Test(Test&) { }

  // But it's convertible to int
  operator int() { return 0; }
};

void f(int) { }
void f(Test) { }

struct WorksFine { };
struct Slurper { Slurper(WorksFine&) { } };
struct Eater { Eater(WorksFine) { } };

void g(Slurper) { }
void g(Eater) { } // chooses this, as expected

int main() {
  // Error, why?
  f(Test());

  // But this works, why?
  g(WorksFine());
}

Fehlermeldung

m.cpp: In function 'int main()':
m.cpp:33:11: error: no matching function for call to 'Test::Test(Test)'
m.cpp:5:3: note: candidates are: Test::Test(Test&)
m.cpp:2:3: note:                 Test::Test()
m.cpp:33:11: error:   initializing argument 1 of 'void f(Test)'

Können Sie mir bitte erklären, warum man funktioniert, aber der andere nicht?

War es hilfreich?

Lösung

Die Überladungsauflösung nimmt die Funktion, die die größte Übereinstimmung mit dem mitgelieferten Argumente. Sie versorgen einen Test. Keine Konvertierung notwendig - Identität Umwandlung verwendet. Somit wählt Funktion Auflösung f (Test). Test kann nicht von rvalue kopiert werden, die Sie geliefert, aber die Überladungsauflösung bereits gelungen ... Umstellung auf int wird nie überprüft.

g(Eater) gewählt, weil die Arten nicht genau übereinstimmen, wird die Identität Umwandlung nicht verwendet wird, und der Compiler hat eine Konvertierungsroutine, dass die Arbeiten zu finden. g(Slurper) nicht, weil Sie ein nicht machen können aus dem mitgelieferten Argumente.

"Warum nicht dieses fehlschlagen: struct A { operator int(); }; void f(A&); void f(int); void g() { f(A()); }"

Da f (A &) ist keine gangbare Überlastung für das bereitgestellte Argument. In diesem Fall ist der Parameter eine Referenz und die Tatsache, dass temps nicht bindet an nicht-const erlaubt wird, um die Auflösung zu bewirken. In diesem Fall ist es tut und die die Version der Funktion wird ein Nicht-Kandidat, nur die eine zu verlassen und es funktioniert.

Andere Tipps

Grundsätzlich für die Überladungsauflösung, wird angenommen, dass ein Objekt vom Typ A kann auf einen des beide unabhängig von einer CV-Qualifikation auf ein Objekt vom Typ A überführt werden.

Von Entwurf n1905:

13.3.3.1: Overloading.Overload Resolution.Best führbare Function.Implicit Umwandlungsfolgen

6 Wenn der Parametertyp ist keine Referenz , die impliziten Konvertierungssequenzmodelle eine kopier Initialisierung des Parameters aus dem Argument Ausdruck. Die implizite Umwandlungsfolge ist die, erforderlich, um das Argument zu konvertieren Ausdruck zu einem R-Wert von der Art des Parameters. [ Hinweis : Wenn die Parameter einen Klassentyp hat, ist dies ein konzeptionelles ist Umwandlung für die Zwecke der Bestimmung 13 definiert ist; die tatsächliche Initialisierung in Bezug auf die Konstrukteurs definiert und ist nicht eine Umwandlung. - Endnote ] Auf Unterschiede in der Top-Level-cv-Qualifikation wird durch die Initialisierung selbst subsumiert und tut stellen keine Umwandlung [ Beispiel : a. Parameter vom Typ A kann aus einem Argument vom Typ const A. initialisiert werden Die implizite Umwandlungsfolge für diesen Fall ist die Identität Sequenz; es enthält keine „Umwandlung“ von A bis konst A. - Ende Beispiel ] Wenn die Parameter einen Klassentyp und das Argument Ausdruck hat den gleichen Typen, die impliziten Umwandlung Sequenz eine Identität Umwandlung . [...]

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top