2015-08-17 7 views
6
class Foo { 
    public: 
    Foo(float b) {} 
}; 

class Bar { 
    public: 
    Bar(Foo foo) {} 
}; 

int main(int argc, char *argv[]) { 
    Bar b1(3.0f); // accept, one implicit convertion happens there. 
    Bar b2 = 3.0f; // error: no viable conversion from 'float' to 'Bar' 
    return 0; 
} 

Warum kompiliert der zweite Ausdruck nicht? Ich erwartete, dass es den gleichen konvertierenden Konstruktor wie den ersten Ausdruck aufrufen würde.Kopierinitialisierung mit impliziter Konvertierung in C++

+0

Versuchen Sie, 'Bar (Foo foo)' in 'Bar (const Foo & foo) zu ändern' –

+4

@RemyLebeau Warum hast du gedacht, dass es funktioniert (tut es nicht)? –

Antwort

7

Aus [dcl.init]:

Andernfalls (das heißt, für die verbleibenden Kopie-initialization Fälle), benutzerdefinierte Konvertierungssequenzen, die vom Quelltyp zu dem Zieltyp umwandeln kann oder (wenn eine Umwandlungsfunktion verwendet wird) zu einer davon abgeleiteten Klasse werden wie in 13.3.1.4 beschrieben gezählt, und die beste ist , die durch Überladungsauflösung (13.3) ausgewählt wird.

Wir können eine benutzerdefinierte Umwandlung aufzurufen, die von der Quelle Typ ist direkt in den Zieltyp. Das heißt, wenn wir Bar(float) hätten, würden wir diesen Konstruktor berücksichtigen. In diesem Fall ist unser Kandidat jedoch einfach Bar(Foo), was keinen float erfordert.

Sie dürfen keine oder eine benutzerdefinierte Konvertierung durchführen. Im Fall der direkten Initialisierung rufen wir einfach Bar(Foo) auf, wodurch eine benutzerdefinierte Konvertierung (float --> Foo) aufgerufen wird. Im Fall der Kopierinitialisierung suchen wir nach einer Konvertierungssequenz von float (dem Quelltyp) bis hin zu Bar (dem Zieltyp), was zwei benutzerdefinierte Konvertierungen (float --> Foo, Foo --> Bar) bedeutet Error.

+1

Wenn der Standard "benutzerdefinierte Konvertierungssequenzen" sagt, zählt genau das. Zum Beispiel gibt der Standard an, dass Konvertierungen direkt im Text des Standards eingeschränkt werden. Aber was ist mit Dingen wie Konvertierungen, die in der Standardbibliothek definiert sind? Sie sagen normalerweise nicht, dass diese "benutzerdefiniert" sind, und ich schätze, dass es Einschränkungen gibt, was der Benutzer in Namespace-Standard tun kann. –

+0

@ChrisBeck Benutzerdefinierte Konvertierungen sind Konvertierungen, die entweder von Konstruktoren (z. B. 'Bar (Foo);') oder Konvertierungsfunktionen (z. B. 'operator Foo();') angegeben werden. – Barry

+0

Barry: yeah Ich schaue jetzt in 12.3.1, es erwähnt keine andere Behandlung für die Standardbibliothek, also schätze ich, dass diese als "benutzerdefiniert" für diese Zwecke gelten –

3

Der zweite Initialisierungstyp wird als Kopierinitialisierung bezeichnet und verwendet den Kopierkonstruktor. Daher erwartet diese Art der Initialisierung, dass die rechte Seite in Bar umwandelbar ist.