C++17 version of the standards introduces if constexpr
. If the constexpr
keyword follows the if
keyword in
an if statement, then the if
condition must be a constant and the then
or else
block is discarded at compile
time, depending on the value of the constant.
More precisely, if constexpr
branches that are discarded are not going to be instantiated. This behavior enables us to write some
overloaded function templates in a more readable way: you don’t need to use complex patterns (eg: by using std::enable_if
) to make code
compile.
This rule points out where a complex overloaded functions template could simply be replaced by if constexpr
.
Noncompliant code example
template<typename Type>
typename std::enable_if_t<std::is_arithmetic_v<Type>> process(Type&& type); // Noncompliant, this function can be combined with the one below
template<typename Type>
typename std::enable_if_t<!std::is_arithmetic_v<Type>> process(Type&& type);
template <typename It, typename Distance>
void moveForward(It& it, Distance d, std::input_iterator_tag); // Noncompliant, this function can be combined with the one below
template <typename It, typename Distance, typename T>
void moveForward(It& it, Distance d, T);
template <typename It, typename Distance>
void moveForward(It& it, Distance d) { // Wrapper of the "moveForward" functions
moveForward(it, d, typename std::iterator_traits<It>::iterator_category{} );
}
Compliant solution
template<typename Type>
void process(Type&& type) {
if constexpr(std::is_arithmetic_v<type>) {
// implementation
} else {
// implementation
}
}
template <typename It, typename Distance>
void moveForward(It& it, Distance d) { // Modifications have been directly done inside the wrapper
if constexpr (std::iterator_traits<It>::input_iterator_tag) {
// implementation
} else {
// implementation
}
}