web-dev-qa-db-fra.com

Existe-t-il une alternative "sûre" à static_cast?

Existe-t-il une alternative "sûre" à static_cast en C++ 11/14 ou une bibliothèque implémentant cette fonctionnalité?

Par "sûr", je veux dire que la distribution ne devrait autoriser que les versions qui ne perdent pas en précision. Ainsi, une conversion de int64_t à int32_t ne sera autorisée que si le nombre est contenu dans un int32_t et sinon une erreur est signalée.

16
Andreas Pasternak

Il y a gsl::narrow

étroit // narrow<T>(x) est static_cast<T>(x) si static_cast<T>(x) == x ou il jette narrowing_error

35
Caleth

Vous avez le cas d'utilisation inversé.

static_cast (et les autres transtypages de style c ++) est destiné à indiquer les intentions du programmeur. Lorsque vous écrivez auto value = static_cast<int32_t>(value_64);, vous dites "Oui, j'ai * vraiment l'intention de * descendre * cette valeur, éventuellement en la tronquant, lorsque j'effectue cette affectation" . En conséquence, un compilateur, qui aurait peut-être eu tendance à se plaindre de cette conversion dans des circonstances normales (comme si vous aviez écrit int32_t value = value_64;), observe à la place "eh bien, le programmeur m’a dit que c’était ce qu’ils voulaient; pourquoi Me mentiraient-ils? " et va compiler le code en silence.

Si vous souhaitez que votre code C++ avertisse ou génère une erreur lors de conversions non sécurisées, vous devez explicitement non utiliser static_cast, const_cast, reinterpret_cast et laisser le compilateur faire son travail. Les compilateurs ont des indicateurs qui modifient la manière dont les avertissements sont traités (le décodage int64_t en int32_t ne produit généralement qu'un avertissement). Veillez donc à utiliser les indicateurs corrects pour forcer les avertissements à être traités comme des erreurs.

21
Xirema

Vous pouvez créer le vôtre avec sfinae. Voici un exemple:

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
}

Cela ne compilera que si la taille que vous avez convertie est> = la taille de la source.

Essayez-le ici

Vous pouvez compliquer cela davantage avec numeric_limits pour les autres types et type_traits .

Notez que ma solution est une solution au moment de la compilation, car vous avez posé la question sur static_cast, où statique désigne ici "déterminé au moment de la compilation".

0