Cleaned up casting guidance

The various guidelines now have consistent Enforcements.
All C-style casts are now consistently banned, including to `(void)`.
Cast to `(void`)` should be `std::ignore =` instead.
All functional-style casts are now consistently banned,  instead of
`T(x)` use `T{x}`.
This commit is contained in:
hsutter 2020-09-29 12:18:16 -07:00
parent c86be249f3
commit 45a68e8ac7

View File

@ -11679,35 +11679,35 @@ In fact, they often disable the general rules for using values.
Overload resolution and template instantiation usually pick the right function if there is a right function to pick. Overload resolution and template instantiation usually pick the right function if there is a right function to pick.
If there is not, maybe there ought to be, rather than applying a local fix (cast). If there is not, maybe there ought to be, rather than applying a local fix (cast).
##### Note ##### Notes
Casts are necessary in a systems programming language. For example, how else Casts are necessary in a systems programming language. For example, how else
would we get the address of a device register into a pointer? However, casts would we get the address of a device register into a pointer? However, casts
are seriously overused as well as a major source of errors. are seriously overused as well as a major source of errors.
##### Note
If you feel the need for a lot of casts, there might be a fundamental design problem. If you feel the need for a lot of casts, there might be a fundamental design problem.
##### Exception The [type profile](#Pro-type-reinterpretcast) bans `reinterpret_cast` and C-style casts.
Casting to `(void)` is the Standard-sanctioned way to turn off `[[nodiscard]]` warnings. If you are calling a function with a `[[nodiscard]]` return and you deliberately want to discard the result, first think hard about whether that is really a good idea (there is usually a good reason the author of the function or of the return type used `[[nodiscard]]` in the first place), but if you still think it's appropriate and your code reviewer agrees, write `(void)` to turn off the warning. Never cast to `(void)` to ignore a `[[nodiscard]]`return value.
If you deliberately want to discard such a result, first think hard about whether that is really a good idea (there is usually a good reason the author of the function or of the return type used `[[nodiscard]]` in the first place).
If you still think it's appropriate and your code reviewer agrees, use `std::ignore =` to turn off the warning which is simple, portable, and easy to grep.
##### Alternatives ##### Alternatives
Casts are widely (mis) used. Modern C++ has rules and constructs that eliminate the need for casts in many contexts, such as Casts are widely (mis)used. Modern C++ has rules and constructs that eliminate the need for casts in many contexts, such as
* Use templates * Use templates
* Use `std::variant` * Use `std::variant`
* Rely on the well-defined, safe, implicit conversions between pointer types * Rely on the well-defined, safe, implicit conversions between pointer types
* Use `std::ignore =" to ignore `[[nodiscard]]` values.
##### Enforcement ##### Enforcement
* Force the elimination of C-style casts, except when casting a `[[nodiscard]]` function return value to `void`. * Flag all C-style casts, including to `void`.
* Warn if there are many functional style casts (there is an obvious problem in quantifying 'many'). * Flag functional style casts using `Type(value)`. Use `Type{value}` instead which is not narrowing. (See [ES.64](#Res-construct).)
* The [type profile](#Pro-type-reinterpretcast) bans `reinterpret_cast`. * Flag [identity casts](#Pro-type-identitycast) between pointer types, where the source and target types are the same (#Pro-type-identitycast).
* Warn against [identity casts](#Pro-type-identitycast) between pointer types, where the source and target types are the same (#Pro-type-identitycast). * Flag an explicit pointer cast that could be [implicit](#Pro-type-implicitpointercast).
* Warn if a pointer cast could be [implicit](#Pro-type-implicitpointercast).
### <a name="Res-casts-named"></a>ES.49: If you must use a cast, use a named cast ### <a name="Res-casts-named"></a>ES.49: If you must use a cast, use a named cast
@ -11767,7 +11767,8 @@ for example.)
##### Enforcement ##### Enforcement
* Flag C-style and functional casts. * Flag all C-style casts, including to `void`.
* Flag functional style casts using `Type(value)`. Use `Type{value}` instead which is not narrowing. (See [ES.64](#Res-construct).)
* The [type profile](#Pro-type-reinterpretcast) bans `reinterpret_cast`. * The [type profile](#Pro-type-reinterpretcast) bans `reinterpret_cast`.
* The [type profile](#Pro-type-arithmeticcast) warns when using `static_cast` between arithmetic types. * The [type profile](#Pro-type-arithmeticcast) warns when using `static_cast` between arithmetic types.
@ -20774,7 +20775,7 @@ Type safety profile summary:
* <a name="Pro-type-constcast"></a>Type.3: Don't use `const_cast` to cast away `const` (i.e., at all): * <a name="Pro-type-constcast"></a>Type.3: Don't use `const_cast` to cast away `const` (i.e., at all):
[Don't cast away const](#Res-casts-const). [Don't cast away const](#Res-casts-const).
* <a name="Pro-type-cstylecast"></a>Type.4: Don't use C-style `(T)expression` or functional `T(expression)` casts: * <a name="Pro-type-cstylecast"></a>Type.4: Don't use C-style `(T)expression` or functional `T(expression)` casts:
Prefer [construction](#Res-construct) or [named casts](#Res-casts-named). Prefer [construction](#Res-construct) or [named casts](#Res-casts-named) or `T{expression}`.
* <a name="Pro-type-init"></a>Type.5: Don't use a variable before it has been initialized: * <a name="Pro-type-init"></a>Type.5: Don't use a variable before it has been initialized:
[always initialize](#Res-always). [always initialize](#Res-always).
* <a name="Pro-type-memberinit"></a>Type.6: Always initialize a member variable: * <a name="Pro-type-memberinit"></a>Type.6: Always initialize a member variable: