美文网首页
万能引用/转发引用

万能引用/转发引用

作者: 404Not_Found | 来源:发表于2022-02-07 22:53 被阅读0次
  • 作者: 雪山肥鱼
  • 时间:20220208 14:45
  • 目的: 转发引用
# 万能引用/转发引用
  ## 类型区别基本含义
  ## 万能引用 基本认识
  ## 万能引用资格的剥夺与比那人
    ## 剥夺
    ## 辨认

万能引用/转发引用

类型区别基本含义

#if 1 //万能引用
/*
void func(const int & abc) {

}
*/

template <typename T>
void func(const T& abc) {
    
}

int main(int argc, char ** argv) {
    func(10);//T 代表的类型是?T 的类型取决于1. 参数10, 2. abc 的类型 即 const T &
    //引出万能引用

    return 0;
}

10 传入到函数模板的参数中,到底是声明类型。

  1. 取决于 10 是声明类型
  2. 取决于 函数模板参数,abc 是声明类型

引出转发引用,即万能引用

万能引用 基本概念

#include <iostream>
using namespace std;

void myfunc(int && tmprv) {
    cout << tmprv << endl;
    return;
}

int main(int argc, char ** argv) {
    //结论:万能引用是一种类型,跟 int 类型一样
    //右值引用是用 &&
    //int && rv = 1000;

    myfunc(10);//10是一个右值,绑在右值引用上。右值做实参
    int i = 100;//i 是左值
    myfunc(i);//错误,右值引用不能绑定左值
    return 0;
}

右值绑在右值引用,没问题。
左值绑在右值引用,是错误的。

补充:

void test(int &a) {

}
void test2(int && a) {

}
int main(int argc, char **argv) {
    test(2);//错误
    return 0;
}

形参 int & 只能接左值
形参 int&& 只能接右值
形参 int 左右都能接

  • 改造成函数模板
    发现,技能接左值,又能接右值
//此时 函数模板既能接左值,又能接右值

template <typename T>
void myfunc(T && tmprv) {//特别注意:&& 和T 没有任何关系
    cout << tmprv << endl;
    return;
}

int main(int argc, char ** argv) {

    myfunc(10);
    int i = 100;

    //此时不能将T 单纯的认为是int,否则一定会因为左值传右值而报错
    myfunc(i);//改成模板后,竟然不报错。

    return 0;
}

注意注释所说,不能单纯的认为 T 的类型是int.
T&& 构成了 tmprv 的类型

上述情形即万能i引用:

  1. 必须是函数模板
  2. 参数必须发生了类型推断,并且函数模板中的形参类型为 T&&(固定的)

T&& 可以当左值,也可以当右值

  • 如果实参是 i,则 T&& 类型被推断为 int &
  • 如果实参是10,则 tmprv的类型会被推断为 int &&
void func(int && abc); //非模板 则 右值引用

template <typename T>
void func(T && tmp){} //是万能引用

template <typename T>
void func(vector<T> && param) {} //右值引用 只有T&& 是万能,可以测一下.另一个原因,T 是要参与类型推断的。此处没有参与类型推断

template<typename T>
void func(vector<T> && param) {

}

vector<int> aa = {1};
func(aa); //即可推断出来

根据第3个例子,auto && template = ... 也是万能引用

模板中的形参依旧是左值,是可以进行赋值的


template <typename T>
void myfunc(T && tmprv) {//特别注意:&& 和T 没有任何关系
    //tmprv 本身是个左值,是可以被赋值的。
    tmprv = 120;
    cout << tmprv << endl;
    return;
}

int main(int argc, char ** argv) {

    int i = 100;
    myfunc(i);
    cout << i << endl;//120
    i = 200;
    myfunc(std::move(i));//i 被 变成了 右值,推断为 int&&

    return 0;
}

需要注意,此时 模板中 T 类型的变化,在传进来之前可是值传递哟,T 不是单纯的int:


T 蜕变成 int &.png

万能引用资格的剥夺与辨认

剥夺

const 会剥夺一个引用成为万能引用的资格,被打回右值引用

template <typename T>
void myfunc(const T && tmprv) {
    cout << tmprv << endl;
    return;
}

int main(int argc, char ** argv) {

    myfunc(10);
    int i = 100;
    myfunc(i);//报错
        myfunc(std::move(i)); //变成右值才可以
    return 0;
}

辨认

template <typename T>
class mytest {
public:
    void testfunc(T && x) {//不是万能引用,而是右值引用

public:
      template <typename T2>
      void testfunc(T2 && x) {
      }

    }
};

int main(int argc, char ** argv) {
    mytest<int> mc;
    int i = 100;
    mc.testfunc(i);//错误,左值绑了右值
        mc.testfunc(std::move(i));

        mc.testfunc2(i);
    return 0;
}

本身是个成员函数,而没有涉及到类型推断,所以不是万能引用.

相关文章

网友评论

      本文标题:万能引用/转发引用

      本文链接:https://www.haomeiwen.com/subject/nsmbkrtx.html