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

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

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

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

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

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

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

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

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

你可能感兴趣的:(学习,c++,开发语言)