简体   繁体   中英

Is there a "safe" static_cast alternative?

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) is static_cast<T>(x) if static_cast<T>(x) == x or it throws narrowing_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM