为什么使用 SFINAE 而不是函数重载?
Why use SFINAE instead of function overloading?
我试图理解 std::enable_if
,在 cppreference.com 有一个例子,这个 using 比函数重载有什么好处?
struct T {
enum { int_t,float_t } m_type;
template <typename Integer,
std::enable_if_t<std::is_integral<Integer>::value, int> = 0
>
T(Integer) : m_type(int_t) {}
>
template <typename Floating,
std::enable_if_t<std::is_floating_point<Floating>::value, int> = 0
>
T(Floating) : m_type(float_t) {} // OK
};
struct T1 {
enum { int_t, float_t } m_type;
T1(int) :m_type(int_t)
{
cout << "int ctor" << endl;
}
T1(float) :m_type(float_t)
{
cout << "float ctor" << endl;
}
};
在这种情况下确实没有真正的优势,因为整数类型将被转换为例如int
首先调用正确的重载构造函数。
但是,假设您想创建一个只接受整数的函数。它应该 return 作为参数接收的整数类型。在这种情况下,手动创建 >10 个重载只是 error-prone/silly/annoying/... 相反,您应该编写如下内容:
template <typename Integer,
std::enable_if_t<std::is_integral<Integer>::value, int> = 0>
Integer doMagic (Integer a) {
return a;
}
你的两个例子不一样。对于第一个示例,class 将排除任何整数或浮点类型 exactly。对于你的第二个例子,你只接受 int
或 float
意味着如果你传递了 long long
或 double
那么你有可能缩小转换,这可能会导致你丢失数据。这与您使用的代码无关,但可以而且应该注意它。
当使用可以转换为 float
或 int
的类型时,您也会遇到歧义。例如
T1 foo{0l};
不会编译但是
T foo{0l};
会。
我试图理解 std::enable_if
,在 cppreference.com 有一个例子,这个 using 比函数重载有什么好处?
struct T {
enum { int_t,float_t } m_type;
template <typename Integer,
std::enable_if_t<std::is_integral<Integer>::value, int> = 0
>
T(Integer) : m_type(int_t) {}
>
template <typename Floating,
std::enable_if_t<std::is_floating_point<Floating>::value, int> = 0
>
T(Floating) : m_type(float_t) {} // OK
};
struct T1 {
enum { int_t, float_t } m_type;
T1(int) :m_type(int_t)
{
cout << "int ctor" << endl;
}
T1(float) :m_type(float_t)
{
cout << "float ctor" << endl;
}
};
在这种情况下确实没有真正的优势,因为整数类型将被转换为例如int
首先调用正确的重载构造函数。
但是,假设您想创建一个只接受整数的函数。它应该 return 作为参数接收的整数类型。在这种情况下,手动创建 >10 个重载只是 error-prone/silly/annoying/... 相反,您应该编写如下内容:
template <typename Integer,
std::enable_if_t<std::is_integral<Integer>::value, int> = 0>
Integer doMagic (Integer a) {
return a;
}
你的两个例子不一样。对于第一个示例,class 将排除任何整数或浮点类型 exactly。对于你的第二个例子,你只接受 int
或 float
意味着如果你传递了 long long
或 double
那么你有可能缩小转换,这可能会导致你丢失数据。这与您使用的代码无关,但可以而且应该注意它。
当使用可以转换为 float
或 int
的类型时,您也会遇到歧义。例如
T1 foo{0l};
不会编译但是
T foo{0l};
会。