使用std :: enable_if作为函数参数和模板参数有什么区别?

时间:2016-06-20 14:53:22

标签: c++ templates metaprogramming function-templates default-arguments

我想知道使用std::enable_if作为函数参数与模板参数之间的区别是什么?

我有以下2个功能模板:

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

生成以下程序集(从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

除了明显不同的是f_function有2个函数参数,f_template有2个模板参数,它们之间有什么区别?是否有任何特殊用途?

1 个答案:

答案 0 :(得分:3)

作为一个简单的例子,你可以这样做:

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

虽然(1)(2)由于显而易见的原因而无法编译(std::string不是可接受的类型),f_template可以即使T不是广告连播类型,也可以使用技巧。

有效的替代方案是:

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

另一个可能是:

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

更隐蔽的一个涉及参数包作为守卫:

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

所有这些都按预期工作,你不能解决它们(至少,我不知道如何做到这一点,但也许有人会带来一个好方法)。