4

Ich frage mich, was ist der Unterschied zwischen der Verwendung von std::enable_if als Funktionsargument vs Vorlage Argument?Was ist der Unterschied zwischen der Verwendung von std :: enable_if als Funktionsargument gegen Vorlage Argument?

Ich habe folgende 2 Funktionsschablonen:

#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); 
} 

die die folgende Anordnung erzeugen (wie von 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 

Neben dem offensichtlichen Unterschied, dass f_function 2 Funktionsparameter und f_template mit 2 Vorlagenargumenten Was sind die Unterschiede zwischen ihnen? Gibt es einen bestimmten Gebrauch von einem über einen anderen?

+1

Sie könnten es sogar zum Rückgabetyp hinzufügen. Abgesehen von dem Stack, der für Ihre erste Version (f_function) benötigt wird, verhalten sich diese ziemlich gleich. – lorro

Antwort

3

Als triviales Beispiel, können Sie dies tun:

int main() { 
    // f_function(std::string{}); // (1) 
    // f_template<std::string>(std::string{}); // (2) 
    f_template<std::string, void>(std::string{}); 
} 

Während (1) und (2) nicht kompilieren aus offensichtlichen Gründen (std::string ist ein ungültiger Typ), kann f_template mit einem Trick verwendet werden, auch wenn T kein Pod-Typ ist.


wäre eine gute Alternative sein:

template<typename T> 
std::enable_if_t<std::is_pod<T>::value> 
f_template(T) 
{ } 

Ein Unbekannter ein, die stattdessen einen Parameter Pack als Wächter beinhaltet:

template<typename T, std::enable_if_t<std::is_pod<T>::value>* = nullptr> 
void f_template(T) 
{ } 

Ein anderes sein könnte

template<typename T, typename..., typename = typename std::enable_if_t<std::is_pod<T>::value>> 
void f_template(T) 
{ } 

Alle diese arbeiten wie erwartet und du kannst nicht um sie herum arbeiten (zumindest weiß ich nicht, wie das geht, aber vielleicht kommt jemand mit einem guten Trick).

+0

Es fehlt im etwas obskureren der Check, dass das Pack leer ist :-). – Jarod42

+0

@ Jarod42 Es macht Sinn, einen Fehler bei der Kompilierung Zeit zu haben, aber es lohnt sich auch, das Gesicht der Entwickler zu betrachten, die versuchen, es mit der unwahrscheinlichsten Folge von Typen zu brechen !! ;-) – skypjack

+0

@ Jarod42 Hinzugefügt und erwähnt. Vielen Dank. – skypjack