【cpp进阶-02】谈谈c++11新特性(1)
auto和decltype
auto
auto+const
类型不是引用时,auto推导抛弃const属性
类型为引用时,auto推导继承const属性
auto注意事项
- 不能成为函数参数列表
- 不能成为类非静态的成员变量
- 不能定义数组
- 需要初始化
decltype
decltype对比auto
auto varname = value;
:定义时需初始化值,类型自动推导。
decltype(exp) varname = value;
:定义时类型由exp决定,无需初始化值。
decltype推导规则
- exp为普通表达式,decltype的类型与exp类型一致
- exp为函数(返回值不为void),decltype的类型与函数返回值一致
- exp为左值 or 带有括号的表达式,deltype的类型为exp的引用类型
返回类型后置
decltype + auto + 返回值后置 共同 完成返回值类型推导
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u)
{
return t + u;
}
using
模板别名
-
typedef:需要模板外敷
template <typename Val> struct str_map { typedef std::map<std::string, Val> type; }; // ... str_map<int>::type map1;
-
using:简化上述流程
template <typename Val> using str_map_t = std::map<std::string, Val>; // ... str_map_t<int> map1;
左值与右值
概念
- 左值:可以在等号左面的值
- 右值:(1)纯右值(2)将亡值:T&&和std::move
注意:
(1)++i是左值,i++是右值
(2)字符串字面量是左值,认为是const char[N]
(3)const T&可以引用左值 or 右值
(4)T&&可以引用std::move(左值)
移动语义
可以理解为转移内存的所有权,对方不再拥有,可以节省拷贝的开销。
【移动构造函数】
A(A&& a)
{
this->data = a.data;
a.data = nullptr;
cout << "move ctor" << endl;
}
//使用
A new_A = std::move(old_A);
A new_A(std::move(old_A));
完美转发
使用函数模板实现为左值和右值转发到不同的函数
(1)函数模板 + T&&:实现万能引用
(2)std::forward<T>(n)
:维持左右值属性,实现完美转发
template <typename T>
void function(T&& t) {
otherdef(forward<T>(t));
}
返回值优化(RVO)
函数需要返回一个对象实例时候,就会创建一个临时对象并通过复制构造函数将目标对象复制到临时对象,这里有复制构造函数和析构函数会被多余的调用到,有代价,而通过返回值优化,C++编译允许省略调用这些复制构造函数。
std::function & std::bind & lambda表达式
1.特殊函数类型
(1)仿函数:类中重载operator()后可以将类看做仿函数
(2)匿名函数(lambda):
[&](int a)->int{return a+1;};
2. 函数指针
typedef int(* PFUNC)(int, int); //别名:类型为int F(int, int);
PFUNC p = A(int, int);//声明
p(1,1);//调用
3. std::function & std::bind
(1)function:函数包装器,使用模板实现不同函数的封装
std::function<int(int)> f1 = [&](int a)->int //int f(int)类型包装器
{
std::cout<<a<<std::endl;
return a;
};
(2)bind:函数适配器,将不同参数列表的函数适配转换
class A{
void my_fun(int a,int b);
}
auto f2 = std::bind(&A::my_fun, &a, 1, std::placeholders::_1); //f2:function<void(int b)>
f2(2);//等价于&A::my_fun(1, 2);
4. 回调函数
【实现信号与槽的机制】
class SignalObject{
private:
function<void(int)> my_callfun; //函数接口
public:
//注册槽函数
void regist(function<void(int)> slotfun){
my_callfun = slotfun;
}
//发射信号,满足条件回调函数
void emitsignal(int singalval){
my_callfun(singalval);
}
};
class SlotObject{
public:
SlotObject(){}
void slotfunction(int singalval){
//cout<<this<<endl;
cout<<"get singal:"<<singalval<<endl;
}
};
int main(){
SignalObject singal;
SlotObject slot;
//step:注册回调函数
singal.regist(bind(&SlotObject::slotfunction, &slot, placeholders::_1));
//step2:信号发生,自动调用slot函数
singal.emitsignal(1);
}