深入应用C++11 笔记 (一)
第一章 程序简洁之道
1.1 类型推导
auto类型推导 (auto–> 类型指示符 type-specifier)
auto x=5; //OK:x-->int auto pi=new auto(1); //OK:pi-->int* const auto *v=&x,u=6; //OK:v-->const int*;u-->const int static auto y=0.0; //OK:y-->double auto int r; //error auto s; //error
auto的限制
void func(auto a=1){} //error:auto不能用于函数参数 struct Foo { auto var1_=0; //error:auto不能用于非静态成员变量 static const auto var2_=0; //OK :var2_---->static const int }; template<typename T> struct Bar{}; int maint(void) { int arr[10]={0}; auto aa=arr; //OK: aa-->int* auto rr[10]=arr; //error :auto 无法定义数组 Bar<int> bar; Bar<auto> bb=bar; //error auto无法推导出模板参数 return 0; }
decltype 关键字
- 获知表达式的类型 : decltype(exp) –>exp表示一个表达式(expression)
- decltype是在编译器推导出一个表达式的类型(并不会正真计算表达式的值)
int x=0; decltype(x) y=1; //y-->int decltype(x+y) z=0; //z-->int const int &i=x; decltype(i) j=y; //j-->const int & const decltype(z) *p=&z; //*p-->const int,p-->const int* decltype(z) *pi=&z; //*pi-->int,pi-->int * decltype(pi) *pp=π //*pp-->int * ,pp-->int **
返回类型后置语法(auto 和decltype的结合使用)
template<typename T,typename U> auto add(T t,U u) -> decltype(t+u) { return t+u; }
int& foo(int &i); float foo(float &f); template<typename T> auto func(T &val) -> decltype(foo(val)) { return foo(val); }
1.2 模板改进
模板的右尖括号(避免 连续两个尖括号(”>>”)会被翻译成右移操作符,而不是模板参数表的结束)
template<int N> struct Foo { //........ }; Foo<(100 >> 2)> xx;//括号
模板的别名 using
typedef std::map<std::string,int> map_int_t; typedef std::map<std::string,std::string> map_str_t;
上面的场景中,其实我们需要的是一个固定以std::sting为key的map,它可以映射到int或另一个std:string。
//在C++98/03中 的写法如下: template<typename Val> struct str_map { typedef std::map<std::string,Val> type; }; //....... str_map<int>::type map1;
//C++11中出现了一个 可以重定义一个模板的语法 using template<typename Val> using str_map_t=std::map<std::string,Val>; //..... str_map_t<int> map1;
通过using可以定义任意类型的模板表达方式,比如:
template<typename T> using type_t = T; //.... type_t<int> i; //type_t 实例化后的类型和它的模板参数类型等价。type_t<int>-->int
函数模板的默认模板参数
在C++98/03中,类模板可以有默认的模板参数,如下:
template<typename T,typename U=int,U N=0> struct Foo { //..... };
但是却不支持函数的默认模板参数:
template<typename T=int>//error //error in C++98/03:default template argumments void func(void) { //..... }
但是这一限制在C++11中被解除。上面的func函数可以在C++11中直接使用。
int main(void) { func();//如同一个普通的void(void)类型函数 return 0; }
函数模板的默认模板参数没有必须卸载参数表的最后限制
我们可以指定函数中的一部分模板参数采用默认参数,而另一部分使用自动推导:
template<typename R=int,typename U> R func(U val) { return val; } int main(void) { auto type=func(123); return 0; }
在调用函数模板时,若显示指定模板的参数,由于参数填充顺序是从右往左的,因此,像下面这样调用:
func<long>(123);//func 的返回类型是long
当默认模板参数和模板参数自动推导同时使用时,若函数模板无法自动推导出参数类型,则编译器将使用默认模板参数;否则将使用自动推导出的参数类型。例如:
template<typename T> struct identity { typedef T type; }; template<typename T=int> void func(typename identity<T>::type val,T=0) { //.... } int main(void) { func(123); //T --> int func(123,123.0); //T --> double return 0; }
在上面例子中,通过identity外敷模板禁用了形参val的类型自动推导,但由于func指定了模板参数T的默认类型为int,因此,在fun(123)中,func的val参数将为int类型。而在func(123,123.0)中,由于func的第二个参数123.0位double类型,模板参数T将优先被自动推导位double。