使用 std::enable_if 作为函数参数与模板参数有什么区别?
What is the difference between using std::enable_if as function argument vs template argument?
我想知道使用 std::enable_if
作为函数参数与模板参数有什么区别?
我有以下两个函数模板:
#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 , %rsp
movl , -4(%rbp)
movl -4(%rbp), %eax
movl [=12=], %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 [=12=], %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 个模板参数之外,它们之间还有什么区别?两者之间有什么特别的用途吗?
作为一个简单的例子,您可以这样做:
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
不是可接受的类型),即使 T
不是 pod 类型,f_template
也可以与技巧一起使用。
一个有效的替代方案是:
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)
{ }
所有这些都按预期工作,你无法绕过它们(至少,我不知道该怎么做,但也许有人会带来一个好技巧)。
我想知道使用 std::enable_if
作为函数参数与模板参数有什么区别?
我有以下两个函数模板:
#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 , %rsp
movl , -4(%rbp)
movl -4(%rbp), %eax
movl [=12=], %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 [=12=], %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 个模板参数之外,它们之间还有什么区别?两者之间有什么特别的用途吗?
作为一个简单的例子,您可以这样做:
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
不是可接受的类型),即使 T
不是 pod 类型,f_template
也可以与技巧一起使用。
一个有效的替代方案是:
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)
{ }
所有这些都按预期工作,你无法绕过它们(至少,我不知道该怎么做,但也许有人会带来一个好技巧)。