使用 SFINAE 将结构作为参数转发到函数模板中

问题描述

我想知道为什么这段代码不能编译:

struct S{ int m; };

template<class T,class = std::enable_if_t<std::is_same_v<T,S>>>
T& operator+=(T&& arg0,int arg1)
{
    arg0.m += arg1;
    return arg0;
}

int main()
{   
    S val0{ 0 }; int val1{ 1 };
    val0 += val1;

    return 0;
}

但是当 SFINAE 被移除或使用基本整数而不是结构体(通过适当的模板代码更改)时,它确实会编译。

解决方法

这里的问题是对于转发引用,由于 val0 是左值,T 被推导出为 S&,而不是 S。这会导致 std::is_same_v<T,S> 失败,因为 SS& 不同。要解决此问题,您可以使用 std::decay_t 删除像

这样的引用
template<class T,std::enable_if_t<std::is_same_v<std::decay_t<T>,S>,int> = 0>
T& operator+=(T&& arg0,int arg1)
{
    arg0.m += arg1;
    return arg0;
}

我还调整了模板以使用默认的非类型参数而不是默认的类型参数。这样做可以让您更轻松地重载函数,因为与默认值不同,默认类型参数不是函数签名的一部分。