Hi,
Is it intended for gsl::narrow_cast<T>(u) and gsl::narrow<T>(u) to only be usable with arithmetic types (so both T and the type of u must be arithmetic)?
In the current GSL implementation, gsl::narrow<T>(u) is being guarded by std::enable_if std::is_arithmetic<T>, but gsl::narrow_cast<T>(u) has no such guards. In fact, gsl::narrow_cast is essentially a wrapper around static_cast.
The guard on gsl::narrow<T>(u) prevents T from being non-arithmetic. Furthermore, the implementation of gsl::narrow will cause the code to fail to compile if static_cast<U>(narrow_cast<T>(u)) != u (where U is the type of u) is not valid. Together with the guard on T, this should prevent non-arithmetic types from being used for either of T or U. However, cases like the following actually slip through. This case does not result in a narrowing implicit/explicit conversion.
struct A
{
A() {}
A(int) {}
operator int() { return 42; }
};
int main() {
A a{42};
gsl::narrow_cast<int>(a); // compiles and executes with no failures/errors
}
Thanks,
Dmitry
Hi,
Is it intended for
gsl::narrow_cast<T>(u)andgsl::narrow<T>(u)to only be usable with arithmetic types (so bothTand the type ofumust be arithmetic)?In the current GSL implementation,
gsl::narrow<T>(u)is being guarded bystd::enable_ifstd::is_arithmetic<T>, butgsl::narrow_cast<T>(u)has no such guards. In fact,gsl::narrow_castis essentially a wrapper aroundstatic_cast.The guard on
gsl::narrow<T>(u)preventsTfrom being non-arithmetic. Furthermore, the implementation ofgsl::narrowwill cause the code to fail to compile ifstatic_cast<U>(narrow_cast<T>(u)) != u(whereUis the type ofu) is not valid. Together with the guard onT, this should prevent non-arithmetic types from being used for either ofTorU. However, cases like the following actually slip through. This case does not result in a narrowing implicit/explicit conversion.Thanks,
Dmitry