33

Der folgende Code in Visual Studio kompiliert 2013 gcc 4.8, klirren 3.4 und Klirren 3.5 (Apple-LLVM 6.0), aber nicht kompiliert in Klirren 3.6 (via Apple LLVM 6.1)Ist diese Änderung in der Überladungsauflösung zwischen Clang 3.5 und 3.6 korrekt oder ein Fehler?

Der Code ist eine vereinfachte Version eines kompliziert Klasse in unserer Codebasis, die mindestens erforderlich ist, um das Problem zu zeigen.

Der Kern des Problems ist, dass die Kopie Konstruktion von TYPED_VALUE ist, in 3,6, für den Typ des templated Umwandlungsoperator Auswertung STRING wegen der Anwesenheit eines Konstruktor, der ein STRING annimmt; Dies führt dazu, dass std::is_constructible ausgewertet wird, was dazu führt, dass die Definition STRING benötigt wird (was wir hier nicht bereitstellen können - würde zu einer zirkulären Abhängigkeit im vollständigen Code führen).

class STRING; 

class TYPED_VALUE 
{ 
public: 
    TYPED_VALUE(const TYPED_VALUE&) = default; // explicit or implicit doesn't make a difference 
    TYPED_VALUE(const STRING &) {} 

    template< typename TYPE, typename std::enable_if<!std::is_pointer<TYPE>::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 > 
    operator TYPE(void) const = delete; 
}; 

class TYPED_STORAGE 
{ 
public: 
    TYPED_STORAGE(const TYPED_VALUE &v) : value(v) {} 

    TYPED_VALUE value; 
}; 

Die Fehlermeldung ist

/type_traits:2329:38: error: incomplete type 'SICORE::STRING' used in type trait expression 
    : public integral_constant<bool, __is_constructible(_Tp, _Args...)> 
            ^
/main.cpp:348:99: note: in instantiation of template class 'std::__1::is_constructible<SICORE::STRING, const SICORE::STRING &>' requested here 
     template< typename TYPE, typename std::enable_if<!std::is_pointer<TYPE>::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 > 
                           ^
/main.cpp:349:9: note: while substituting prior template arguments into non-type template parameter [with TYPE = SICORE::STRING] 
     operator TYPE(void) const = delete; 
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/main.cpp:355:56: note: while substituting deduced template arguments into function template 'operator type-parameter-0-0' [with TYPE = SICORE::STRING, $1 = (no value)] 
     TYPED_STORAGE(const TYPED_VALUE &v) : value(v) {} 
                ^
/main.cpp:340:11: note: forward declaration of 'SICORE::STRING' 
    class STRING; 
     ^

Für mich wie ein Fehler in 3.6 scheint, in früheren Versionen der Überladungsauflösung der Kopierkonstruktor feststellt, dass die Template-Argumente zu bewerten, ohne dass die beste Lösung ist - Ich habe versucht, die Überladung Auflösung Hinweise in der Norm zu verstehen, aber ich denke, dass nur verwirrt mich mehr;)

(Dies kann behoben werden, indem entweder der Konstruktor oder der Konvertierungsoperator explizit ich realisiere, aber das ist nicht das Verhalten wir wollen)

Irgendwelche Standardexperten da draußen kennen die Antwort?

+3

Dies kann unter [temp.inst]/7 fallen "Wenn der Überladungsauflösungsprozess die korrekte Funktion zum Aufrufen ohne Vorlage einer Klassen- Vorlagendefinition bestimmen kann, ist nicht angegeben, ob diese Instanziierung tatsächlich stattfindet." – dyp

+3

Um @ dyps Kommentar zu erweitern, funktioniert die Überladungsauflösung im Allgemeinen in drei Schritten: 1) Aufzählung aller möglichen Kandidatenfunktionen; 2) Bestimmen der Umwandlungssequenzen, die für jedes Argument für jeden Kandidaten erforderlich sind (und Entfernen nicht lebensfähiger Kandidaten); 3) vergleiche die Umwandlungssequenzen für die beste Übereinstimmung. Wenn wir diese Prozedur bis zum Buchstaben befolgen, dann wird das 'is_constructible' * immer * instanziiert, aber der Standard gibt dem Compiler Spielraum, ihn nicht zu instantiieren, wenn er die richtige Funktion zum Aufrufen bestimmen kann. –

+0

Ok danke Jungs, ich werde mir überlegen wie ich den gewünschten Effekt auf andere Weise erreichen kann! –

Antwort

-1

Vorlagen werden bei Bedarf instanziiert, und ich denke, Clang 3.6 implementiert eine DR, wo es eine Vorlage früher als 3.5 benötigt wurde.

0

Der Kopierkonstruktor von TYPED_VALUE verwendet einen Verweis auf STRING, es sollte nicht ausgewertet werden.
Ich denke, das ist ein kling Fehler.
Ich habe den neuen C++ - Standard lange nicht gelesen, konnte aber nicht sicherstellen, dass er sich nicht geändert hat.

1

ich Clang glauben ist richtig, diesen Fehler zu erzeugen:

Der [temp.inst] -Abschnitt des C++ Standard in Ziffer 10 sagt:

If a function template or a member function template specialization is used in a way that involves overload resolution, a declaration of the specialization is implicitly instantiated (14.8.3).

Er bildet die implizite Konvertierung Sequenz notwendig den Rang Überladungskandidaten für den Aufruf von TYPE_VALUEs Konstruktor erfordern die Instantiierung des Konvertierungsoperators. Und die Verwendung eines unvollständigen Typparameters für das Merkmal bildet keinen ungültigen Typ. Dies ist also kein Substitutionsfehler, sondern ein schwerer Fehler.