Is there a "safe" alternative to static_cast
in C++11/14 or a library which implements this functionality?
By "safe" I mean the cast should only allow casts which do not lose precision. So a cast from int64_t
to int32_t
would only be allowed if the number fits into a int32_t
and else an error is reported.
There's gsl::narrow
narrow //
narrow<T>(x)
isstatic_cast<T>(x)
ifstatic_cast<T>(x) == x
or it throwsnarrowing_error
You've got the use-case reversed.
The intended use of static_cast
(and the other c++-style casts) is to indicate programmer intentions. When you write auto value = static_cast<int32_t>(value_64);
, you're saying "Yes, I very much *intend* to downcast this value, possibly truncating it, when I perform this assignment" . As a result, a compiler, which might have been inclined to complain about this conversion under normal circumstances (like if you'd have written int32_t value = value_64;
) instead observes "well, the programmer has told me that this is what they intended; why would they lie to me?" and will silently compile the code.
If you want your C++ code to warn or throw an error on unsafe conversions, you need to explicitly not use static_cast
, const_cast
, reinterpret_cast
, and let the compiler do its job. Compilers have flags that change how warnings are treated (downcasting int64_t
to int32_t
usually only results in a Warning), so make sure you're using the correct flags to force warnings to be treated as errors.
Assuming the question is about compile-time detection of potentially lossy conversions...
A simple tool not mentioned yet here is that list initialization doesn't allow narrowing, so you can write:
void g(int64_t n)
{
int32_t x{n}; // error, narrowing
int32_t g;
g = {n}; // error, narrowing
}
NB. Some compilers in their default mode might show "warning" and continue compilation for this ill-formed code, usually you can configure this behaviour via compilation flags.
You can create your own with sfinae. Here's an example:
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
}
This will compile only if the size you cast to is >= the source size.
Try it here
You can complicate this further using numeric_limits for other types and type_traits .
Notice that my solution is a compile-time solution, because you asked about static_cast
, where static here refers to "determined at compile-time".
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.