2014-12-01 13 views
5

Der folgende Code funktioniert:Warum wird eine benutzerdefinierte Konvertierung während der Initialisierung angewendet?

#include <iostream> 

struct B 
{ 
    operator int() 
    { 
     return int(); 
    } 
}; 

struct A 
{ 
    A(int, int){ std::cout << "A(int, int)" << std::endl; } 
}; 

A a({B(), B()}); 

int main() 
{ 
} 

und erzeugt eine Ausgabe:

A(int, int) 

DEMO

Aber ich kann, warum nicht bekommen? Was die Norm sagt, ist:

Wenn man jedoch das Argument einer Konstruktor oder benutzerdefinierte Konvertierungsfunktion, die ein Kandidat von 13.3.1.3 ist, wenn für das Kopieren aufgerufen/der temporären in den zweiten Bewegungs Schritt eine Klasse kopieren-Initialisierung, durch 13.3.1.7 bei der Übergabe der Initialisierung Liste als ein einzelnes Argument oder wenn die Initialisierungsliste genau ein Element und eine Umwandlung in eine Klasse X oder Verweis auf (möglicherweise cv-qualifiziert) X gilt für den ersten Parameter eines Konstruktors von X [...] nur Standardkonvertierungssequenzen und Ellipsenumwandlungssequenzen werden berücksichtigt ed

Also in unserem Fall betrachteten wir das Argument des Konstruktors (es war {B(), B()}). Genauer gesagt, haben wir die Initialisiererliste als einzelnes Argument übergeben (der zweite Fall in der von mir zitierten Regel). Nun müssen wir das erste Element der Initialisiererliste (temporär vom Typ B) in int konvertieren, und die einzige Möglichkeit besteht darin, die benutzerdefinierte Konvertierung anzuwenden (B::operator int()). Aber wie am Ende der Regel gesagt wurde, die ich zitiert habe, wurden nur Standard-Umwandlungssequenzen und Ellipsen-Umwandlungssequenzen als betrachtet. Da sollte dieser Code nicht funktionieren, sollte es den Fehler wie A(int, int) ist nicht lebensfähig oder Art von werfen.

Was ist los? Kann es sein, dass es ein Fehler ist?

+0

Kann dieses Zitat in N4140 nicht finden. Welchen Entwurf und welchen Absatz zitieren Sie? – Columbo

+0

@Columbo: C++ 11 13.3.3.1/4 –

+0

mögliches Duplikat von [Unterscheidung zwischen benutzerdefinierten Konvertierungssequenzen durch die anfängliche Standardkonvertierungssequenz] (http://stackoverflow.com/questions/11555950/differencing-between-user -defined-conversion-sequences-by-the-initial-standard) –

Antwort

1

Der Wortlaut war fehlerhaft und wurde mit C++ 14 geändert. Jetzt [over.best.ics]/4 reads

Wenn jedoch das Ziel ist

  • der erste Parameter eines Konstruktors oder
  • [...]

und der Konstruktor oder benutzerdefinierte Konvertierungsfunktion ist ein Kandidat von

  • 13.3.1.3, , wenn das Argument in der zweiten Stufe einer Klasse copy-Initialisierung, die zeitlich begrenzt ist
  • 13.3.1.4, 13.3.1.5, 13.3.1.6 oder (in allen Fällen) oder
  • die zweite Phase vom 13.3.1.7, wenn die Initialisiererliste hat genau ein Element, und das Ziel ist der erste Parameter eines Konstruktors der Klasse X, und die Umwandlung zu X oder Verweise auf (möglicherweise cv-qualifiziert) X,

user -definierte Konvertierungssequenzen werden nicht berücksichtigt. [] Hinweis: Diese Regeln verhindern, dass während der Überladungsauflösung mehr als eine benutzerdefinierte Konvertierung angewendet wird, wodurch eine unendliche Rekursion vermieden wird. - Endnote]

Die Umwandlung von B() zu int wird hierdurch nicht abgedeckt - die kühne Ausdruck appertains nur auf die Bindung eines Hinweises auf eine temporäre während des Kopierens-Initialisierung.
jedoch Clang rejects this sample code gemäß dem oben:

class A; 

struct B 
{ 
    operator A(); 
}; 

struct A 
{ 
    A(A const&){} 
}; 

A a{B()}; 
+0

Großartig, danke !!! –