bugprone-incorrect-enable-if¶
Detects incorrect usages of std::enable_if
that don’t name the nested
type
type.
In C++11 introduced std::enable_if
as a convenient way to leverage SFINAE.
One form of using std::enable_if
is to declare an unnamed template type
parameter with a default type equal to
typename std::enable_if<condition>::type
. If the author forgets to name
the nested type type
, then the code will always consider the candidate
template even if the condition is not met.
Below are some examples of code using std::enable_if
correctly and
incorrect examples that this check flags.
template <typename T, typename = typename std::enable_if<T::some_trait>::type>
void valid_usage() { ... }
template <typename T, typename = std::enable_if_t<T::some_trait>>
void valid_usage_with_trait_helpers() { ... }
// The below code is not a correct application of SFINAE. Even if
// T::some_trait is not true, the function will still be considered in the
// set of function candidates. It can either incorrectly select the function
// when it should not be a candidates, and/or lead to hard compile errors
// if the body of the template does not compile if the condition is not
// satisfied.
template <typename T, typename = std::enable_if<T::some_trait>>
void invalid_usage() { ... }
// The tool suggests the following replacement for 'invalid_usage':
template <typename T, typename = typename std::enable_if<T::some_trait>::type>
void fixed_invalid_usage() { ... }
C++14 introduced the trait helper std::enable_if_t
which reduces the
likelihood of this error. C++20 introduces constraints, which generally
supersede the use of std::enable_if
. See
modernize-type-traits for another tool
that will replace std::enable_if
with
std::enable_if_t
, and see
modernize-use-constraints for another
tool that replaces std::enable_if
with C++20 constraints. Consider these
newer mechanisms where possible.