I wonder what is the difference between using std::enable_if
as function argument vs template argument?
I have the following 2 function templates:
#include <type_traits>
template<typename T>
void f_function(T, typename std::enable_if_t<std::is_pod<T>::value, int> = 0)
{
}
template<typename T, typename = typename std::enable_if_t<std::is_pod<T>::value>>
void f_template(T)
{
}
int main()
{
int x = 1;
f_function(x);
f_template(x);
}
which produce the following assembly (as from https://godbolt.org/g/ON4Rya):
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $1, -4(%rbp)
movl -4(%rbp), %eax
movl $0, %esi
movl %eax, %edi
call void f_function<int>(int, std::enable_if<std::is_pod<int>::value, int>::type)
movl -4(%rbp), %eax
movl %eax, %edi
call void f_template<int, void>(int)
movl $0, %eax
leave
ret
void f_function<int>(int, std::enable_if<std::is_pod<int>::value, int>::type):
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
nop
popq %rbp
ret
void f_template<int, void>(int):
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
nop
popq %rbp
ret
Besides the obvious difference being that f_function
having 2 function parameters and f_template
having 2 template arguments what are the differences between them? Is there any particular use of one over another?
In C++ metaprogramming, std::enable_if is an important function to enable certain types for template specialization via some predicates known at the compile time. Using types that are not enabled by std::enable_if for template specialization will result in compile-time error.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
As a trivial example, you can do this:
int main() {
// f_function(std::string{}); // (1)
// f_template<std::string>(std::string{}); // (2)
f_template<std::string, void>(std::string{});
}
While (1) and (2) do not compile for obvious reasons (std::string
is not an accepted type), f_template
can be used with a trick even if T
is not a pod type.
A valid alternative would be:
template<typename T, std::enable_if_t<std::is_pod<T>::value>* = nullptr>
void f_template(T)
{ }
Another one could be:
template<typename T>
std::enable_if_t<std::is_pod<T>::value>
f_template(T)
{ }
A more obscure one that involves a parameter pack as a guard instead:
template<typename T, typename..., typename = typename std::enable_if_t<std::is_pod<T>::value>>
void f_template(T)
{ }
All these ones work as expected and you cannot work around them (at least, I don't know how to do that, but maybe someone will come with a good trick).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With