• C++学习之十二


    1)std::forward的补充

    template<typename T>
    void func(T&& tmprv){}
    
    int main()
    {
    	int i = 18;
    	func(i); //i是左值,T = int&, tmprv = int&;
    	func(100); //100是右值,T = int,tmprv = int&&;
    
    	int a = 10;
    	//std::forward中,根据T的类型,推断是左值引用还是右值引用,结合func函数模板的类型推导案例!
    	int& rst = std::forward<int&>(a); //如果std::forward里面的是左值,那就返回一个左值
    	int&& rst1 = std::forward<int>(a); //如果std::forward里面的是右值,那就返回一个右值
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2)auto类型推导(常规推导)
    auto的使用说明:
    auto推断发生在编译期间
    是根据变量的初始值进行类型推断;
    auto的叫法:类型占位符
    auto相当于函数模板的T,如void func(typename T){}!推导出来的类型都完全相同。
    形参的三种方式:传值方式,传引用或者指针方式,传万能引用方式;

    2.1)传值方式:
    int j = 10;
    const auto& i = j;//auto = int
    //传值方式书写格式:auto 后面直接写变量名;
    auto xy2 = i; //传值方式:引用类型被抛弃,const属性也被抛弃,把对方看成是新的副本,是一个新的生命诞生!!
    2.2)传引用方式
    const auto& i = j;//auto = int 的推断方式和函数模板的推断方式完全等价,测试如下:
    template<typename T>
    void tm(const T& tmprv){} //调用tm函数模板,则T = int, tmprv = int const &; 
    int i = 10;
    const auto* px = &i; //auto = int //const int* px = i; //引用会被抛弃掉,没它啥事。
    2.3)万能引用方式
    int j = 10;
    auto&& t = j;	//因为x是左值,所以auto = int&; 理论上推导出来的语句是 int& && t = j;
    		//但是系统发生了引用折叠,(因为有左值引用,最终就为左值引用),所以最终结果是:int& t = j;
    2.4) auto推导函数指针或者引用
    void func(int a, int b)
    {
    	cout << "a: " << a << " b " << b << endl;
    }
    int main()
    {	
    	auto f1 = func; //void(*)(int,int),推导出来的是函数指针
    	auto& f2 = func; //void(&)(int,int)//函数引用
    	f1(1, 2); f2(3, 4); 
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    auto总结:
    传值方式:const属性也被抛弃,引用类型被抛弃;
    引用(指针)方式:const属性会被保留,引用(指针)类型被抛弃;
    万能引用方式:如果是左值,则推导为int&,如果是右值,则推导为int&&;
    3)decltype的使用方法

    decltype():圆括号是变量
    	int a = 2;
    	const int& i = a;
    	decltype(i) m = i; //如果decltype中是个变量,则变量的const属性和引用属性都会被返回。这是根auto的最大区别;
    3.2)decltype():圆括号是表达式
    返回的是表达式结果的类型。
    	int a = 20;
    	int* ptr = &a;
    	decltype(*ptr) m = a; //m的类型是 = int&;
    	//说明:首先,"*ptr"是一个表达式,不是变量(因为*ptr = 4;是可以编译通过的);
    	//并且这个表达式能够作为等号左边内容,则返回的是一个引用;
    3.2)decltype():圆括号是函数
    int func(int a)
    {
    	cout << a << endl; //不会执行这条语句
    	return 5;
    }
    int main()
    {	
    	decltype(func(5)) m = 6; //可不是这么写:"decltype(func) m",要有函数名,还得有括号,如果有参数,还得写参数
    	decltype(func) m1; //返回类型是 int(int); //这个有返回类型,有参数类型,代表的是一个可调用对象;
    	std::function<decltype(func)> f1 = func; //声明了一个function(函数)类型,用来代表一个可调用对象;//所代表的可调用对象就是:“ int(int)”;
    	f1(34); //函数调用测试
    	cout << "hello world" << endl;
    	return 0;
    }
    
    3.3)decltype主要用于模板编程中,应付可变类型,测试代码如下:
    template<class T>
    class Test
    {
    public:
    	//typename T::const_iterator iter; //常规写法
    	decltype(T().begin()) iter; //“T()”,可以生成临时对象,
    	void getBegin(T& tmp)
    	{
    		iter = tmp.begin();
    	}
    };
    
    int main()
    {	
    	using vecInt = const std::vector<int>; //vector别名
    	vecInt v1{ 1,2,3 };
    	Test<vecInt> test;
    	test.getBegin(v1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.4)小插曲,再次理解临时对象

    class A
    {
    public:
    	A() { cout << "A constructor " << endl; }
    	~A() { cout << "A deConstructor " << endl; }
    	void func(void) { cout << "func--------" << endl; }
    };
    
    int main()
    {	
    	A().func(); //创建临时对象,并调用对象的func函数,因为没有人接,所以调用完就析构了,昙花一现的感觉。
    	cout << "main-------" << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.5)返回类型后置(尾置返回类型)

    
    using namespace std;
    int tf(int& num)
    {
    	cout << "int func" << endl;
    	return num;
    }
    
    float tf(float& num)
    {
    	cout << "float func" << endl;
    	return num;
    }
    
    template<typename T>
    auto funcTmp(T& tv)->decltype(tf(tv)) //auto没有自动类型推导的含义,它只是返回类型后置语法的一部分。
    {
    	return tf(tv);
    }
    int main()
    {	
    	float fnum = 1.3;
    	cout << funcTmp<float>(fnum) << endl;
    	int inum = 3;
    	cout << funcTmp<int>(inum) << endl;
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    4)std::bind和 std::function
    4.1)类成员函数指针(可调用对象)

    #include 
    using namespace std;
    
    class TC
    {
    public:
    	void fun(int tv)
    	{
    		cout << "TC::fun()非静态成员函数执行了,tv = " << tv << endl;
    	}
    };
    
    int main()
    {
    	TC tc;
    	void(TC::*pfun)(int) = &TC::fun; 
    	//void(TC::*pfun)(int)中,因为是属于类的,所以加"TC::",如果没有类,void(*pfun)(int),则跟普通函数指针没区别!
    	(tc.*pfun)(50); // 对象tc通过类成员函数指针pfun调用成员函数fun()
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4.2)std::function绑定类的静态成员函数和非静态成员函数

    class A
    {
    public:
    	static int staticFunc(int t)
    	{
    		cout << "static hello world" << endl;
    		return t + 5;
    	}
    	int func(int t)
    	{
    		cout << "hello world" << endl;
    		return t + 5;
    	}
    };
    
    int main()
    {
    	std::function<int(int)> f = &A::staticFunc; //绑定类的静态成员函数
    	cout << f(5) << endl;
    
    	std::function<int(A,int)> f2 = &A::func; 
    	cout << f2(A(), 100) << endl;
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4.3)std::function应用与回调函数

    #include 
    #include
    
    using namespace std;
    class CB
    {
    public:
    	std::function<void()> fcallback;
    	CB(const std::function<void()>& f):fcallback(f)
    	{
    		int i;
    		i = 1;
    	}
    	void runCallback(void)
    	{
    		fcallback();
    	}
    };
    
    class CT
    {
    public:
    	void operator()(void)
    	{
    		cout << "operator------run" << endl;
    	}
    };
    
    int main()
    {
    	CT ct; //ct是可调用对象
    	CB cb(ct); //cb需要可调用对象做参数来构造,ct因为有operator(),所以可以转为std::function&对象;
    	cb.fcallback(); //执行了CT里面的operator();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4.4)绑定成员函数

    class A
    {
    public:
    	int func(int a, int b)
    	{
    		cout << "a " << a << ",b " << b << endl;
    		return a + b;
    	}
    };
    
    int main()
    {
    	A a1;
    	auto fn = std::bind(&A::func, &a1, std::placeholders::_1, 5); //绑定成员函数,必须有对象
    	cout << fn(10) << endl;
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    我转行做版图工程师,还是IC验证好呢?怎么选!一文秒懂
    UE5报错及解决办法
    pubsub消息订阅与发布
    【ZYNQ-嵌入式】zynq学习笔记(二)—— GIPO的硬件配置和软件配置
    Python 人工智能 Machine Learning 机器学习基础知识点详细教程(更新中)
    Android SELinux访问向量规则
    无线渗透AIREPLAY-NG使用
    Android 12之启动画面Splash Screens(二) -- framework原理
    ElasticSearch快速入门实战
    YOLOv5算法改进(11)— 主干网络介绍(MobileNetV3、ShuffleNetV2和GhostNet)
  • 原文地址:https://blog.csdn.net/qq_30143193/article/details/132717942