4

Ich habe in meinem Projekt mit expliziten Konvertierungsoperatoren für Templates experimentiert, um eine explizite Konvertierung von benutzerdefinierten variantenähnlichen Typen zu implementieren. Das minimal Beispiel mein Problem reproduzieren sieht wie folgt aus (in C++ 14-Modus):Priorität und Ambiguität von expliziten Konvertierungsoperator-Vorlagen

#include <iostream> 
#include <stdexcept> 
#include <cmath> 

using namespace std; 

class A 
{ 
     public: 
     template<typename T> explicit operator T() const // 1 
     { 
       cout << "operator T" << endl; 
       return T(); 
     } 

     template<typename T> explicit operator const T&() const // 2 
     { 
       cout << "operator const T&" << endl; 
       throw runtime_error("operator const T&"); 
     } 

     template<typename T> explicit operator T&() // 3 
     { 
       cout << "operator T&" << endl; 
       throw runtime_error("operator T&"); 
     } 


}; 


int main(int, char**) 
{ 
     try 
     { 
       const A& a = A(); 
       cout << abs(static_cast<double>(a) - 3.14) << endl; 
     } 
     catch (const runtime_error&) 
     { 

     } 

     return 0; 
} 

Das Problem, das ich sah sich der Betreiber für die static_cast Umwandlung gewählt ist. Mit dem GCC ist es ein erwarteter (1) Fall. Die Ausgabe lautet:

operator T 
3.14 

Aber Clang lehnt dies mit der folgenden Ausgabe zu kompilieren:

main.cpp:37:20: error: ambiguous conversion for static_cast from 'const A' to 'double' 
      cout << std::abs(static_cast<double>(a) - 3.14) << endl; 
          ^~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:10:32: note: candidate function [with T = double] 
    template<typename T> explicit operator T() const 
           ^
main.cpp:16:32: note: candidate function [with T = double] 
    template<typename T> explicit operator const T&() const 
           ^
1 error generated. 

Warum Clang Umwandlung (2) ist die Auffassung, wenn es anscheinend zusätzlichen Konstruktoraufruf in der Umwandlungsfolge erfordern würde, während (1) würde nicht? Und ist es richtig (und GCC ist dann falsch) dies zu tun?

+0

Aber warum würden Sie das überhaupt tun? Was ist der Punkt, der sowohl '' Operator T() '' und '' Operator Const T & '' hat? –

+1

@ArneVogel Die Absicht davon im realen Code war, alternative Umwandlungssequenzen zu liefern, z. B. wenn die Variante "long double" enthält, dann würde 'operator T()' helfen, sie nach "int" zu transformieren. Aber anscheinend missverstehe ich Dinge, die 'static_cast' tatsächlich ausführt, also ist diese Umwandlung in Wert in der Tat überflüssig. – aclex

Antwort

0

static_cast führt entweder implizite Konvertierung oder direkte Initialisierung durch. In Ihrem Fall ist die implizite Konvertierung nicht praktikabel, aber die direkte Initialisierung ist, da static_castexplicit constructors and conversion functions berücksichtigt. Also meine Vermutung ist, dass Clang (meiner Meinung nach richtig) identifiziert, dass es zwei mögliche direkte Initialisierungen gibt und beschwert sich entsprechend. Ich bin mir nicht sicher, was in GCC vorgeht, vielleicht ist es operator T(), wenn es einen findet, egal ob es andere gibt.

+0

Ja, ich stimme dem zu. Offensichtlich führt 'static_cast' keine explizite benutzerdefinierte Umwandlung, wie sie ist, ohne direkte Initialisierung von' new-type' durch, und für diese Initialisierung erscheinen sowohl 'operator T' als auch 'operator const T & amp;' geeignet. Danke, dass Sie darauf hingewiesen haben. Noch ist nicht ganz klar, wie die passende benutzerdefinierte Konvertierung gewählt wird. Wenn die Konvertierungsprozedur eine implizite Konvertierung ist, aber auch definierte explizite Konvertierungen berücksichtigt, basiert die Auflösung auf der Möglichkeit der Kopienkonstruktion, und ja, beide Operatoren sind gleichermaßen dafür geeignet. – aclex