2017-01-19 3 views
0

Nehmen wir an, ich ein Makro wie dieses:static_cast <T> vs T (n) für Grundtypen

#define IS_SIGNED_B(T) (static_cast<T>(-1)<0) 

Wäre es in Ordnung, es zu schreiben, wie

#define IS_SIGNED_B(T) (T(-1)<0) 

Zu wissen, dass T (sollte) immer ein grundlegender Typ sein. Und verschiedene andere Fälle, wo ich einen bestimmten Wert brauche, um explizit von einem bestimmten Typ zu sein.

Ich weiß, diese Fragen für Situationen wie verursachen können:

signed char(0); 

Aber zu wissen, dass ich Grundtypen haben typedef als:

typedef signed char Int8; 
Int8(0); 

es irgendwelche anderen Fragen, die nicht das? Kann der Konstruktor eines fundamentalen Typs als identisch mit einem statischen Cast betrachtet werden?

EDIT: Ich weiß über die Existenz von std::numeric_limits und std::is_signed. Dies war nur ein Beispiel. Nicht der tatsächliche Fall. Ich entschuldige mich, dass ich das nicht erwähnt habe.

+2

Persönlich würde ich all dies vermeiden und uns ['std :: numeric_limits :: is_signed'] (http://en.cppreference.com/w/cpp/types/numeric_limits/is_signed) – NathanOliver

+2

Warum brauchen Sie ein Makro dafür, wenn ['std :: is_signed'] (http://en.cppreference.com/w/cpp/types/is_signed) existiert? – Borgleader

+0

Sie scheinen unter dem Eindruck zu stehen, dass 'T (-1)' den Konstruktor von 'T' für' T == int' aufruft, dies ist jedoch nur eine alternative Syntax für einen C-Style-Cast, der wahrscheinlich als implementiert ist 'static_cast', also sollte es keinen Unterschied geben. – nwp

Antwort

3

Kann der Konstruktor eines grundlegenden Typs als identisch mit einem statischen Modell betrachtet werden?

Grundlegende Typen haben keine Konstruktoren. Int8(0) ist eine explizite Typkonvertierung und alternative Syntax für (Int8)0. Dies wird als C-Style-Cast bezeichnet. Die alternative Syntax wird als Funktionsausdruck bezeichnet.

Für grundlegende Integraltypen entspricht C-Style Cast einem Static_cast. Aber es ist im Allgemeinen nicht gleichwertig. Wenn kein static_cast verfügbar ist, führt es reinterpret_cast (oder const_cast oder die Kombination von const_cast und einer der anderen Umwandlungen aus).

Gibt es noch andere Probleme?

Ich verstehe nicht ganz, was Problem oder Probleme, die Sie vorgestellt haben, aber ja explizite Typ Konvertierungen haben große Probleme. Das Hauptproblem ist, dass Programmierer nicht perfekt sind, und Sie können nicht davon ausgehen, dass T is (should) always be a fundamental type immer gilt. Sie möchten, dass der Compiler solche Fehler feststellt. Ein C-Style-Cast wird einige der Fehler, die Sie oder Ihre Kollegen möglicherweise machen, verbergen und Fehlermeldungen durch undefiniertes Verhalten ersetzen.

Vielleicht besteht im Zusammenhang mit Ihrem Makro wenig Gefahr von undefiniertem Verhalten, aber wie Sie sagten, war das nur ein Beispiel. Eine gute Faustregel: Verwenden Sie lieber den genauen Typ von * _cast, den Sie beabsichtigen, anstatt C-Style-Cast einen der Casts aussuchen zu lassen, die möglicherweise nicht Ihren Vorstellungen entsprechen.

+0

Danke. Das alles wollte ich wissen. Ob es sich um einen statischen oder einen C-Style Cast handelt. Es nervt mich seit einiger Zeit und ich glaube, ich habe die Fälle vergessen, in denen ich das klar verstehen musste. Ich entschuldige mich dafür, dass ich die Frage nicht richtig gestellt habe. –

1

Die erste Sache, die Sie tun sollten, ist aufhören, den C-Präprozessor unnötig zu verwenden.

Verwenden Sie einfach std::is_signed.

dass Anderenfalls, so etwas wie:

template<class T> 
constexpr 
std::integral_constant<bool, 
    (static_cast<T>(-1)<0) 
> is_signed_b() { return {}; } 

, die eine industrielle Stärke Version des Makros ist.

Es gibt eine leere Klasse zurück, die eine constexpr-Konvertierung zu bool hat, deren Wert das gewünschte Ergebnis ist. Es kann zur Kompilierzeit ausgewertet werden (in der Tat ist es schwer, es nicht zu sein).


Aber was ist falsch an Ihrem Makro?

Zunächst sollte Ihr Makro lesen:

#define IS_SIGNED_B(...) (static_cast<__VA_ARGS__>(-1)<0) 

weil

IS_SIGNED_B(std::tuple_element_t<some_tuple, Is>)... 

Pausen unnötig bei der Implementierung.

Der C-Präprozessor versteht C++ nicht. Es versteht nicht, dass , s nicht mehr in () oder {} enthalten sind.

Wie bereits erwähnt, wenn T ein Zwei-Wort-Typ ist, bricht Ihr Code.

Ein anderes Problem ist, dass, wenn Sie es einen Typ füttern, der nicht ein integraler Typ ist, können seltsame Dinge passieren. C-Style-Umwandlungen sind stark und funktionieren für Zeigertypen. So erhalten Sie den Zeiger-Typ von -1 auf der linken Seite. Auf der rechten Seite erhalten Sie 0, die implizit in den Nullwert eines beliebigen Zeigertyps konvertiert. Dann werden die Dinge verglichen. Dieser Absatz enthält alle Arten von undefiniertem Verhalten.