2015-04-18 14 views
7

Betrachten Sie das folgende Stück Code:Chaining Benutzer Umwandlungen in C++

#include <iostream> 

struct C 
{ 
    C() 
    { 
     std::cout << "C()\n"; 
    } 

    explicit C(const C&) 
    { 
     std::cout << "C(const C&)\n"; 
    } 

    operator int() 
    { 
     std::cout << "int()\n"; 
     return 1; 
    } 

    C(int) 
    { 
     std::cout << "C(int)\n"; 
    } 
}; 

int main() 
{ 
    C c1; 
    std::cout << '\n'; 
    C c2 = c1; 
    std::cout << '\n'; 
    C c3(c1); 
} 

Beide g++ und clang geben die folgende Ausgabe:

C() 

int() 
C(int) 

C(const C&) 

Ist es nicht die Regel brechen sagen, dass eine implizite Konvertierung Sequenz kann aus höchstens einer Benutzerkonvertierung bestehen?

+0

Welche Ausgabe haben Sie erwartet? – sehe

+1

Ich könnte mich irren, aber 'C (int)' nimmt ein 'int'. 'C -> int 'ist eine benutzerdefinierte Konvertierung. Ich verstehe nicht, warum "int-> C" in dieser Sequenz enthalten wäre. Es ist eher wie 'std :: string s (someObjectWithACstrConversion);'. Die Funktion, die Sie aufrufen, ist zufällig etwas, das als Konvertierung an anderer Stelle verwendet werden kann. – chris

+0

@sehe Ich würde einen Compilerfehler erwarten. – piotrekg2

Antwort

8

Dies wird nur kompiliert, weil Sie die Klasse C mit sich selbst in der Zeile C c2 = c1; initialisieren. Wenn Sie eine Klasse hätten, die sich genauso verhält wie C und versucht, D d; C c = d;, würde es nicht kompilieren für den Grund, den Sie angegeben: Weil die implizite Konvertierung zwei benutzerdefinierte Konvertierungen erfordern würde. Demonstation

Der Grund es kompiliert, wenn die gleiche Klasse besteht darin, dass copy-Initialisierung (A x = y;) verhält sich anders, wenn y vom Typ A oder daraus abgeleitet. In diesem Fall wird ein Konvertierungskonstruktor ausgewählt, und dieser Konstruktor wird dann mit dem Argument y aufgerufen, was zu einer impliziten Konvertierung führen kann. Der Konstruktoraufruf selbst ist nicht Teil der impliziten Konvertierung.

Also in Ihrem Code, die Konvertierungssequenz enthält nur eine benutzerdefinierte Umwandlung: C zu int, als Konstruktor C(int) separat aufgerufen wird.

See C++ 14 8.5/17:

  • If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s).
  • Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated [...]

mehr bei http://en.cppreference.com/w/cpp/language/copy_initialization lesen.