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.
Il y a gsl::narrow
étroit //
narrow<T>(x)
eststatic_cast<T>(x)
sistatic_cast<T>(x) == x
ou il jettenarrowing_error
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.
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".