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