Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between using std::enable_if as function argument vs template argument?

Tags:

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?

like image 515
Patryk Avatar asked Jun 20 '16 14:06

Patryk


People also ask

What is the purpose of std :: Enable_if?

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.

What is a template argument?

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.


1 Answers

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).

like image 54
skypjack Avatar answered Sep 28 '22 21:09

skypjack