2016-10-08 1 views
1

In einer sehr einfachen Situation mit, die Prüfung für die Konvertierbarkeit des Arguments, wird ein Fehler in Klirren produziert, aber nicht in g ++:Kein Mitglied benannten Wert in std :: is_convertible, wenn sie mit einem eingeschränkten Konstruktor Klirren

#include <type_traits> 

template <class T, class U> 
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value; 

template <class T> 
struct A 
{ 
    template <class S, class = std::enable_if_t<Convertible<S,T>> > 
    A(S const&) {} 
}; 

int main() 
{ 
    A<double> s = 1.0; 
} 

Vielleicht ist das Problem

Der Fehler Klirren gibt zu Is clang's c++11 support reliable? bezogen, lautet:

error: no member named 'value' in 'std::is_convertible<double, A<double> >' 
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value; 
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~^ 

ich habe versucht

  • g ++ - 5,4, g ++ - 6,2 (kein Fehler)
  • Klappern ++ - 3.5, Klappern ++ - 3.8, Klappern ++ - 3.9 (Fehler)

mit Argumente -std=c++1y und für clang entweder mit -stdlib=libstdc++ oder -stdlib=libc++ .

Welcher Compiler ist korrekt? Ist es ein Fehler in clang oder gcc? Oder ist das Verhalten aus bestimmten Gründen nicht definiert und somit beide Compiler korrekt?

Antwort

3

Zunächst einmal beachten Sie, dass es gut funktioniert, wenn Sie verwenden:

A<double> s{1.0}; 

Stattdessen kommt der Fehler aus der Tatsache, dass Sie dies tun:

A<double> s = 1.0; 

die Linie Betrachten unten (extrahiert aus der Definition von Convertible):

std::is_convertible<U,T>::value 

In Ihrem Fall ist dies gesehen wie folgt (einmal Substitution durchgeführt wurde):

std::is_convertible<double, A<double>>::value 

Der Compiler sagt dies deutlich in der Fehlermeldung.

Dies ist, weil eine temporäre A<double> von 1.0 aufgebaut wird, dann ist es s zugeordnet.
Beachten Sie, dass Sie in Ihrer Klassenvorlage einen (mehr oder weniger) Catch-All-Konstruktor definiert haben, so dass auch eine const A<double> & akzeptiert wird.
Beachten Sie außerdem, dass eine temporäre Bindung an eine Konstante const.

Das heißt, passiert der Fehler, weil im Rahmen der std::enable_if_t wir haben, dass A<double> ein unvollständiger Typ ist und aus dem Standard, den wir haben dies für std::is_convertible:

Von und Bis werden vollständige Typen sein [. ..]

Siehe here für den Arbeitsentwurf.

Deshalb würde ich sagen, dass es ein undefiniertes Verhalten ist.


Als Anregung, brauchen Sie nicht std::enable_if_t in diesem Fall zu verwenden.
Sie haben keine Funktionen, aus denen Sie in Ihrem Beispiel die beste auswählen können.
A static_assert ist gut und Fehlermeldungen sind schöner:

template <class S> 
A(S const&) { static_assert(Convertible<S,T>, "!"); } 
+0

Vielen Dank! Das erklärt mir sehr viel. Das "Catch-All" -Argument und der Konstruktionspfad waren für mich die Erkenntnis und führten zu einer Lösung in einem viel größeren Kontext (Der ursprüngliche Code enthält viele verschiedene Vorlagenkonstruktoren, so dass der Fehler-Nachrichten-Ansatz nicht eingreifen konnte) – spraetor

+0

So * Warum * Ist 'std :: is_convertible >' Haben Sie kein ':: value' Member? Ich dachte, dass es ein "Wert" -Mitglied haben soll, das "falsch" ist? –

+0

Ich denke ich sehe jetzt. Ich denke, dass es für die Implementierung von 'std :: is_convertible >' notwendig ist, zu testen, ob der Konstruktor von 'A ' ein 'double' akzeptiert, das rekursiv die Implementierung von' std benötigt: : is_convertible > 'in einer eigenen Definition, an welcher Stelle der Fehler auftritt, weil' std :: is_convertible > 'selbst dort unvollständig ist. –

Verwandte Themen