为什么使用SFINAE而不是函数重载

Why use SFINAE instead of function overloading?

本文关键字:函数 重载 SFINAE 为什么      更新时间:2023-10-16

我正在努力理解std::enable_if,在cppreference.com上有一个例子,使用它比函数重载有什么好处?

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

您的两个示例不相同。在第一个例子中,类将完全地排除任何整数或浮点类型。在第二个例子中,您只接受intfloat,这意味着如果您传递了long longdouble,那么您就有可能进行窄范围转换,这可能会导致数据丢失。这与您正在使用的代码无关,但可以而且应该注意它。

使用可以转换为floatint的类型时,也会出现歧义。例如

T1 foo{0l};

不会编译,但

T foo{0l};

意志。

在这种情况下,确实没有真正的优势,因为整数类型将首先转换为例如int,然后调用正确的重载构造函数。

但是,假设您想要创建一个只接受整数的函数。它应该返回作为参数接收的整数类型。在这种情况下,手动创建>10个重载只是容易出错/愚蠢/令人讨厌/。。。相反,你会写这样的东西:

template <typename Integer,
std::enable_if_t<std::is_integral<Integer>::value, int> = 0>
Integer doMagic (Integer a) {
return a;
}