2017-04-07 2 views
1

Meine Frage ist, ob der folgende Code gültig ist:static_assert in nicht initialisiert Template-Klasse mit gültiger Spezialisierung

template<int i> class Class 
{ 
    static_assert(sizeof(i) == 0, "Class instantiated with i != 1"); 
}; 

template<> class Class<1> {}; 

Dieser Code-Schnipsel kompiliert mit g++. Aber clang++ wird durch die static_assert gefangen:

error: static_assert failed "Class instantiated with non-int type" 

Eine Vorlage, die einen Typ verwendet anstelle eines int wie

template<typename T> class Class 
{ 
    static_assert(sizeof(T) == 0, "Class instantiated with non-int type"); 
}; 

template<> class Class<int> {}; 

wird von beiden Compiler akzeptiert. Für Funktionsvorlagen gilt genau das gleiche Muster.

Ich fand open-std.org::Non-dependent static_assert-declarations, aber das scheint nicht zu gelten, weil meine static_assert ist abhängig von der Vorlage Parameter.

können Sie überprüfen das beschriebene Verhalten auf godbolt.org

EDIT: Wie Johan Lundberg im Kommentar weist darauf hin, meine Frage ist falsch. Tatsächlich hängt sizeof(i) nicht von dem Vorlagenparameter ab. Auch R.Sahu hat völlig recht: Es wäre viel sinnvoller, i != 1 zu behaupten. Dafür akzeptieren beide Compiler den Code.

Allerdings kompiliert immer noch das obere Beispiel mit g++. Als open-std.org::Non-dependent static_assert-declarations gilt für diesen Fall (ich entschuldige mich wieder für die falsche Frage in dieser Hinsicht): Ist g++ eigentlich falsch bei der Kompilierung des Codes ohne Fehler?

+5

Ich glaube nicht, dass Sie richtig sind in "weil mein static_assert ist auf den Template-Parametern abhängig.". sizeof (i) hängt nicht vom * Wert * von i ab. –

+0

Warum verwenden Sie sizeof im ersten Beispiel? i ist vom Typ int und sizeof (i) ist dasselbe wie sizeof (int). Vielleicht in der Behauptung, die Sie direkt verwenden möchten. – Fabio

+2

Wollten Sie 'static_assert (i! = 1," Klasse instanziiert mit i! = 1 ") verwenden? –

Antwort

1

Klirren ++ ist richtig Ihren Code abzulehnen, aber g ++ ist nicht falsch, um den Fehler nicht zu finden; Dies ist eine Situation, in der keine Diagnose erforderlich ist.

Der Standard definiert Ausdrücke innerhalb einer Vorlage streng als "typabhängig" und/oder "wertabhängig". Gegeben template<int i>, i ist Wert-abhängig, aber nicht typabhängig.

[14.6.2.2/4]: Expressions of the following forms are never type-dependent (because the type of the expression cannot be dependent):

  • ...
  • sizeofunary-expression
  • ...

[14.6.2.3/2]: Expressions of the following form are value-dependent if the unary-expression or expression is type-dependent or the type-id is dependent:

  • sizeofunary-expression
  • ...

So ist sizeof(i) nicht abhängig.Schließlich

, 14,6/8 sagt:

If a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, the program is ill-formed; no diagnostic is required.

0

Erstens, wenn Sie, dass die Vorlage behaupten wollen hat sich mit dem falschen Typ instanziiert wurde, müssen Sie in der static_assert explizit sein:

#include <type_traits> 

template<typename T> class Class 
{ 
    static_assert(std::is_same<T, int>::value, "Class instantiated with non-int type"); 


}; 

Zweitens, die folgende Zeile nicht tun können, was Sie denken:

template<> class Class<int> {}; 

Was du eigentlich hier tun, ist eine ganz neue Spezialisierung zu schaffen, die nichts hat überhaupt Class<T> mit dem Standard-Template-Spezialisierung zu tun.

Löschen der Spezialisierung für int und Instanziierung eine nicht-int-Klasse der Standard Spezialisierung ergibt in beiden Compiler einen Fehler, wie es sollte:

int main() 
{ 
    Class<int> ci; 
    Class<float> cf; 
} 

Beispiel Fehler:

<source>: In instantiation of 'class Class<float>': 
<source>:14:18: required from here 
<source>:5:5: error: static assertion failed: Class instantiated with non-int type 
    static_assert(std::is_same<T, int>::value, "Class instantiated with non-int type"); 
    ^~~~~~~~~~~~~ 
+0

Danke für deine Antwort. Aber ich denke deine Idee ist etwas anders als meine. Ich denke an eine Klasse, die keine (nützliche) Standardimplementierung hat, aber mehrere (nicht nur eine) Spezialisierungen anbietet. Dadurch kann ich während der Kompilierung die entsprechende Implementierung auswählen. Der 'static_assert' liefert nur eine lesbare Fehlermeldung. – marlam

+0

@marlam right ... aber bedenke, dass jede Spezialisierung, die du definierst, eine ganz neue Klasse repräsentiert, die nicht die 'static_assert' enthält. Sie definieren 'Class ', nicht instanziieren. –

+0

Richtig, das habe ich gemeint. Es würde der Idee entgegenwirken, wenn die 'static_assert' in jeder Spezialisierung wären. Allerdings stehen wir jetzt noch mit der Frage, warum 'g ++' das erste Snippet akzeptiert (siehe die Bearbeitung in der Frage). – marlam