wake-up-neo.com

Gibt es eine "sichere" static_cast-Alternative?

Gibt es eine "sichere" Alternative zu static_cast in C++ 11/14 oder eine Bibliothek, die diese Funktionalität implementiert?

Mit "sicher" meine ich, dass der Cast nur Casts zulassen sollte, die die Präzision nicht verlieren. Ein Cast von int64_t nach int32_t wäre also nur zulässig, wenn die Nummer in einen int32_t passt und andernfalls ein Fehler gemeldet wird.

16

Es gibt gsl::narrow

schmal // narrow<T>(x) ist static_cast<T>(x), wenn static_cast<T>(x) == x oder narrowing_error

35
Caleth

Sie haben den Anwendungsfall rückgängig gemacht.

Die beabsichtigte Verwendung von static_cast (und den anderen C++ - Stilarten) dient dazu, die Absichten des Programmierers anzugeben. Wenn Sie auto value = static_cast<int32_t>(value_64); schreiben, sagen Sie "Ja, ich habe die Absicht, diesen Wert herunterzuspielen, möglicherweise zu kürzen, wenn ich diese Zuweisung durchführe" . Ein Compiler, der sich unter normalen Umständen (wie zB, wenn Sie int32_t value = value_64; geschrieben hätten) über diese Konvertierung beschweren wollte, beobachtet stattdessen "Nun, der Programmierer hat mir gesagt, dass dies das ist, was sie beabsichtigen, warum würden sie mich anlügen? " und wird den Code lautlos kompilieren.

Wenn Sie möchten, dass Ihr C++ - Code bei unsicheren Konvertierungen warnt oder einen Fehler ausgibt, müssen Sie explizit not static_cast, const_cast, reinterpret_cast verwenden und den Compiler seine Arbeit erledigen lassen. Compiler verfügen über Flags, die die Art und Weise ändern, wie Warnungen behandelt werden (Downcasting von int64_t nach int32_t führt normalerweise nur zu einer Warnung). Stellen Sie daher sicher, dass Sie die richtigen Flags verwenden, um zu erzwingen, dass Warnungen als Fehler behandelt werden.

21
Xirema

Sie können mit sfinae Ihre eigenen erstellen. Hier ist ein Beispiel:

template <typename T, typename U>
typename std::enable_if<sizeof(T) >= sizeof(U),T>::type 
safe_static_cast(U&& val)
{
    return static_cast<T>(val);
}

int main()
{
    int32_t y = 2;
    std::cout << safe_static_cast<int32_t>(y) << std::endl;
    std::cout << safe_static_cast<int16_t>(y) << std::endl; // compile error
}

Dies wird nur kompiliert, wenn die Größe, in die Sie umwandeln,> = Quellgröße ist.

Probier es hier

Sie können dies durch die Verwendung von numeric_limits für andere Typen und type_traits weiter verkomplizieren.

Beachten Sie, dass meine Lösung eine Kompilierzeitlösung ist, da Sie nach static_cast gefragt haben, wobei statisch hier auf "zur Kompilierzeit bestimmt" verweist.