Ich habe Probleme zu verstehen, die Auswirkungen der Konvertierungsfunktion Vorlage Argument Deduktionsregeln in der C++ - Standard. Der Standard gibt an, dass ([temp.deduct.conv] Klausel 1, in §14.8.2.3.1 N4594):Auswirkungen der Konvertierung Funktionsvorlage Argumentabzug in C++
Template argument deduction is done by comparing the return type of the conversion function template (call it P) with the type that is required as the result of the conversion (call it A; see 8.5, 13.3.1.5, and 13.3.1.6 for the determination of that type) as described in 14.8.2.5.
wo 14.8.2.5 ([temp.deduct.type]) der Abschnitt ist, der beschreibt, allgemeine Vorlage Argumentabzug (obwohl der häufigste Fall, Funktion Anruf Vorlage Argument Abzug [temp.deduct.call], scheint nicht mehr darauf hindeuten, hat es jemals?). Der nächste Satz ist das, was mich verwirrt, obwohl (Ziffer 2):
If P is a reference type, the type referred to by P is used in place of P for type deduction and for any further references to or transformations of P in the remainder of this section.
Für mich scheint zu implizieren, dass template <class T> operator T()
und template <class T> operator T&()
gleich sind (und beide Angabe in einer Mehrdeutigkeit führen würde). Aber das ist in keinem Compiler der Fall! Zum Beispiel:
struct any1 { template <typename T> operator T() { } };
struct any2 { template <typename T> operator T&() { } };
void f1(int) { }
void f2(int&) { }
void f3(int const&) { }
int main() {
f1(any1());
// f2(any1()); compile time error
f3(any1());
f1(any2());
f2(any2());
f3(any2());
}
Aber wenn Referenzen ignoriert werden, any1
und any2
sollten das gleiche Verhalten haben, nicht wahr? Natürlich nicht, da f2(any1())
nicht mit gcc oder clang kompiliert, während f2(any2())
kompiliert mit beiden.
Die nächste Klausel (Klausel 3, insbesondere 3.3) verwechselt Dinge noch weiter:
If A is not a reference type: [...] If P is a cv-qualified type, the top level cv-qualifiers of P’s type are ignored for type deduction.
Dies, zusammen mit Satz 2 über die Entfernung von Referenzen, würde zu implizieren scheint, dass der folgende Code soll da nicht kompiliert eine Mehrdeutigkeit:
struct any3 {
template <typename T> operator T&() { }
template <typename T> operator T const&() { }
};
void f1(int) { }
int main() {
f1(any3());
}
und doch funktioniert dies sowohl mit gcc und Klappern in Ordnung.
Was fehlt mir?
bearbeiten
ich, dass die Art und Weise damit umgehen ist genau das Klirren und gcc-Compiler klären sollte, was ich von einem allgemeinen (relativ weit fortgeschritten) Verständnis von C++ erwarten. Einige Kommentatoren haben um Klärung gebeten, was meine Verwirrung ist (und implizit, warum ich mich darum kümmern sollte). Meine Verwirrung hier bezieht sich ausschließlich auf den Versuch, die Implikationen des Standards zu verstehen. Ich brauche ein klares Verständnis davon, weil ich ein Papier mit Code einreiche, der stark von dieser Arbeit abhängt und davon, dass ich normkonform verwende.
Bitte geben Sie an, was in Ihrem ersten Code unerwartet ist und was erwartet wird. Haben Sie erwartet, dass die kommentierte Zeile kompiliert wird? Was bedeuten die anderen Linien? Die T-Zeile der kommentierten Zeile ist "int", soweit ich das sehen kann. Ein 'int' prvalue kann nicht verwendet werden, um ein 'int &' zu initialisieren. Während die Abzüge für die Fälle "T &" und "T" dieselben sein können, wird die Umwandlungsfunktion in einem Fall eine Referenz zurückgeben, und in der anderen nicht. Dies scheint mir klar zu sein. –
@ JohannesSchaub-litb geklärt, danke.Der Punkt ist, dass, wenn Verweise in "P" ignoriert werden, wie der Standard zu implizieren scheint, "any1" und "any2" dasselbe Verhalten haben sollten. Der erste Code funktioniert so, wie ich es vom Raten erwarten würde, bevor ich den Standard lese (dh ein Prvalue kann nicht an eine Lvalue - Referenz, sondern an eine Lvalue - Referenz binden), aber er stimmt nicht mit dem überein, was ich beim Lesen der Standard. Das ist der Punkt der Verwirrung - die Interpretation des Standarddokuments selbst –
Für den zweiten Fall denke ich, dass die zweite Vorlage spezialisierter ist und daher für die benutzerdefinierte Konvertierungssequenz ausgewählt wird (dies ist einer der Tie-Breaker, da ansonsten es wäre eine Zweideutigkeit). –