您的位置:首页 > 编程语言 > C语言/C++

C++新特性学习(3)

2015-07-28 22:13 691 查看

易用性方面

改进的右“>”括号解析

C++11中,定义模板实例时,不再需要小心地在多个连续的大于号之间添加空格了。不必再担心模板定义中的“>>”被解析为右移操作。

auto类型推导

C++11重新定义了auto关键字,该关键字修饰的变量可以使变量在编译时令编译器自动进行变量类型推导。比如下列代码:
double foo();
auto x = 1; //x类型自动推导为int
auto y = foo(); //y类型自动推导为double

struct m { int i; }str;
auto str1 = str; //str1类型自动推导为m;

auto z; //z没有初始化,无法推导
z = x;


变量z在使用auto来声明时没有立即对其初始化,编译器会编译不过。因此auto声明的变量必须立即被初始化。从这个意义上讲,auto并非一种“类型”声明,而是一种类型声明时的“占位符”,编译器在编译时会将auto代替为变量的实际类型。

decltype类型推导

decltype的类型推导并不是像auto一样从变量声明的初始化表达式获取变量的类型。Decltype总是以一个普通的表达式为参数,返回该表达式的类型。与auto相同的一点是,作为一个类型指示符,decltype可以将获得的类型来定义另外一个变量。Decltype类型推导也是在编译时进行的。
#include <typeinfo>
#include <iostream>
using namespace std;

int main() {
int i;
decltype(i) j = 0 ;
cout << typeid(j).name() << endl; //打印出i,g++表示int

float a;
double b;
decltype(a + b) c;
cout << typeid(c).name() << endl; //打印出d,g++表示double
}


对于decltype(e)类型推导时,编译器将依据以下四个规则:
(1) 如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译时的错误。
注意:所有除去关键字、字面量等编译器需要使用的标记外,程序员自定义的标记(token)都可以是标记符。单个标记符对应的表达式就是标记符表达式。
如int arr[4],arr就是一个标记符表达式。
(2) 否则,假设e的类型是T,如果e是一个将亡值,那么decltype(e)的类型为T &&。
(3) 否则,假设e的类型是T,如果e是一个左值,则decltype(e)的类型为T&。
(4) 否则,假设e的类型是T,则decltype(e)的类型为T。
<pre name="code" class="cpp">#include <typeinfo>
#include <iostream>
using namespace std;
int i = 4;
int arr[5] = {0};
int *ptr = arr;

struct S { double d; } s;

void Overloaded(int);
void Overloaded(char);

int && RvalRef();

const bool Func(int);

//规则1:单个标记符表达式以及访问类成员,推导为本类型
decltype(arr) var1; //int[5],标记符表达式
decltype(ptr) var2; //int*,标记符表达式
decltype(s.d) var3; //double,成员访问表达式
decltype(Overloaded) var4; //无法编译

//规则2:将亡值,推导为类型的右值引用
decltype(RvalRef()) var5 = 1; //int &&

//规则3:左值,推导为类型的引用
decltype(true ? i: i) var6 = i; //int&,三元运算符,返回一个i的左值
decltype((i)) var7 = i; //int&,带圆括号的左值
decltype(++i) var8 = i; //int&,++i返回i的左值
decltype(arr[3]) var9 = i; //int&,[]操作返回左值
decltype(*ptr) var10 = i; //int&, *操作返回左值
decltype("lval") var11 = "lval"; //g++输出为A5_c,暂未找到该类型解释,字符串字面常量为左值

//规则4:以上都不是,退到为本类型
decltype(1) var12; //int,除字符串外字面常量为右值
decltype(i++) var13; //int,i++返回右值
decltype((Func(1))) var14; //const bool,这里圆括号可忽略。




“->”追踪返回类型

C++11支持使用auto关键字和->操作符返回值后置的方式追踪返回值类型,主要用于泛型编程进行类型推导式动态编程。例如:
template<class Lhs, class Rhs>
auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}

这种语法主要用来帮助完成模板定义时的类型推断——在上例中,由于用来推断返回类型的“lhs”和“rhs”在“adding_func(...)”之前还未定义,因此必须将返回值类型定义延迟到参数列表之后。应注意到,使用这种后置语法时,函数原来指定返回值类型的位置必须记做“auto”。

基于范围的for循环

C++98:

如果要在for循环中遍历一个数组,常常需要如下编写:
int array[10] = {0,1,2,3,4,5,6,7,8,9};
for ( int *p = array ; p < array + sizeof(array)/sizeof(array[0]) ; p++ )

C++11:

支持“for-each”操作。上面的for循环可改为:
for (int &e : array)
for循环中由”:”分了两部分,第一部分是范围内用于迭代的变量,第二部分则表示将被迭代的范围。
使用基于范围的for循环有一些条件:
(1) for循环的迭代范围是可确定的。对于类来说,类有begin和end函数限制迭代范围;对于数组来说,数组的第一个和最后一个元素限定范围。
(2) 要求迭代的对象实现++和==等操作符。
注意:基于范围的循环使用在标准库的容器中时,如果使用auto来声明迭代的对象的话,那这个对象不会是迭代器对象,而是解引用后的对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: