C++ 中的函数模板专用化和右值引用

Function template specialization and rvalue reference in c++

本文关键字:引用 专用 函数模板 C++      更新时间:2023-10-16
    #include <iostream>
    struct Cls{double dval = 0;};
    template<typename T>
    void foo(T&& Obj) {
        //..... use Obj
    } 
    void foo(const Cls& Obj) {
        //..... use Obj.dval
    }
    //void foo(Cls Obj) {
    //    //..... use Obj.dval
    //}
    int main()
    {
        Cls Obj;
        const Cls cv_Obj;
        foo(Obj); //case 1
        foo(Cls{}); //case 2
        foo(cv_Obj); //case 3
        foo(10.10);
    }

如果函数参数const ref,则Cls的模板专用化将失败(case 1, case 2),但by val适用于所有情况。

除了pass by val之外,还有其他方法可以处理所有cases(所有值类型)的专用化吗?

您可以使用

SFINAE 解决此问题,但是摆脱 _struct 上的重载并为operator<<定义重载会容易得多:

std::ostream& operator<<(std::ostream& os, const _struct& obj)
{
  os << obj.dval;
  return os;
}

使用 SFINAE 解决的一种可能性是检查在一个重载中直接输出Obj的有效性,并根据另一个重载中的_struct检查类型:

template<typename T>
auto foo(T&& Obj) -> decltype(std::cout<<Obj, void()) {
    std::cout<<Obj;
}
template<typename T, 
         std::enable_if_t<std::is_same<_struct, std::decay_t<T>>::value>* = nullptr>
void foo(T&& Obj) {
    std::cout<<Obj.dval;
} 

你需要一个帮助程序结构:

#include <iostream>
struct _struct{double dval = 0;};
template<typename T, typename Enable = void>
struct bar {
    bar(T&& Obj) {
        std::cout<<Obj;
    }
};
template<typename T>
struct bar<T, typename std::enable_if<std::is_same<typename std::decay<T>::type, _struct>::value>::type> {
    bar(T&& Obj) {
        std::cout<<Obj.dval;
    }
};
template<typename T>
void foo(T&& Obj) {
    bar<T>(std::forward<T>(Obj));
}
int main()
{
    _struct Obj;
    const _struct cv_Obj;
    foo(1);
    foo(Obj); //case 1
    foo(_struct{}); //case 2
    foo(cv_Obj); //case 3
    foo("test");
}