With the introduction of if constexpr
in c++17
, some problems which were solved by using compile-time SFINAE in c++14
/c++11
can now be solved using if constexpr
, with an easier syntax.
Consider, e.g., the following basic example of a compile-time recursion to produce a subroutine which prints a variable number of arguments.
#include <iostream>
#include <type_traits>
template <typename T>
void print_sfinae(T&& x)
{
std::cout << x << std::endl;
}
template <typename T0, typename... T>
std::enable_if_t<(sizeof...(T) > 0)> print_sfinae(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
print_sfinae(std::forward<T>(rest)...);
}
template <typename T0, typename... T>
void print_ifconstexpr(T0&&x, T&&... rest)
{
if constexpr (sizeof...(T) > 0)
{
std::cout << x << std::endl;
print_ifconstexpr(std::forward<T>(rest)...);
}
else
std::cout << x << std::endl;
}
int main()
{
print_sfinae(5, 2.2, "hello");
print_ifconstexpr(5, 2.2, "hello");
return 0;
}
The routine print_sfinae
uses SFINAE techniques from c++11
, whereas print_ifconstexpr
does the same job by using if constexpr
.
Can one assume that the compiler, on evaluating the if constexpr
completely discards the non-verified condition and generate code only for the branch which satisfy the if constexpr
condition? Does the standard specifies such a behavior for the compiler?
More generally, in terms of efficiency and generated code, are solutions based on if constexpr
identical to the equivalent solutions based on pre-c++17 SFINAE?
print
can be written as a non-recursive one-liner if you use C++17 fold expressions. Pre-C++17 the same thing could be accomplished using the dummy array trick. – Liquorint dummy[] = {0, ((std::cout << xs << std::endl), 0)...}; static_cast<void>(dummy); // Avoid warning for unused var
– Jarret