C++11新特性——模板空格、自动类型推导、基于范围的循环等等

这篇文章将从C++的模板空格、自动类型推导、基于范围的循环等等几个方面探讨C++11的新特性。

模板空格

在C++98当中,我们如果要定义一个优先队列,可能需要使用以下的代码

#include <iostream>
#include <vector>
#include <deque>
#include <queue>

using std::cout;
using std::endl;
using std::vector;
using std::deque;
using std::priority_queue;

int main ()
{
    priority_queue<int, vector<int>,std::greater<int> > queue; //1
}

注意到,在C++98当中,在注释1所在的行,greater和>之间需要一个空格,否则C++编译器将会把两个连在一起的>运算符识别为一个>>运算符。
而在C++11中,我们可以不写这个空格

#include <iostream>
#include <vector>
#include <deque>
#include <queue>

using std::cout;
using std::endl;
using std::vector;
using std::deque;
using std::priority_queue;

int main ()
{
    priority_queue<int, vector<int>,std::greater<int>> queue; //1
}

nullptr

C++11当中添加了关键字nullptr来表示空指针,而在C++98当中,我们只能够使用0或者NULL来表示空指针,而在有些时候,C++会将0和NULL识别为一个整数,而不是指针,从而导致程序与我们的预期不符,如下例:

#include <iostream>

using std::cout;
using std::endl;

void fun(int * p)
{
    cout << "pointer!\n";
}
void fun(int x)
{
    cout << "integer!\n";
}
int main ()
{
    fun(NULL);     // 1
}

当我们调用fun(NULL)的时候(注释1),与两个重载的函数都匹配,可能会导致编译不同通过,而我们使用nullptr来调用,就会调用指针作为参数的那个函数。

#include <iostream>

using std::cout;
using std::endl;

void fun(int * p)
{
    cout << "pointer!\n";
}
void fun(int x)
{
    cout << "integer!\n";
}
int main ()
{
    fun(nullptr);     // 1
}

程序输出poinnter!,与我们的预期是一致的。

自动类型推断

C++11还可以使用auto关键字进行自动的类型推断。

#include <iostream>

using std::cout;
using std::endl;

int main ()
{
    auto x = 1;
    auto y = 3.1415926;
    auto z = 1ll;
    auto a = x;

    auto lambda = [x,y,z]() mutable -> int{
        z *= y;
        return x * 5;
    };
}

根据赋值号右边的数据类型,auto可以推断出我们定义的左值的类型,比如,通过1这个整数,推断出x的类型为int,通过3.1415936这个浮点数,推断出y是一个double,通过1ll这个long long,推断出z是一个long long,通过x是int,推断出a也是int。最后,我们一般是很难写出一个λ表达式的类型的,于是借助auto可以让编译器帮我们自动的推断。

循环

C++11还提供了一种和java类似的for循环,如下所示

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

int main ()
{
    string strings[5]{"hello world!","hello C++11!","weixin_45644430","$$$$","#######"};

    for(auto str : strings)    //1
        cout << str << endl;
}

在上述代码当中,我们首先定义了一个字符串数组,然后遍历输出它。
在注释1所在的行,在for循环中,我们定义了一个str,我们没有明确地指定它的类型,而是使用了auto关键字,让编译器为我们推导str的类型,这里,编译器会为我们推出str的类型是string。
在循环的过程当中,会遍历strings数组当中的每一个string实例,然后将它赋值给str,然后在输出str。
如果我们要修改str会如何?看下面的代码:

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

int main ()
{
    string strings[5]{"hello world!","hello C++11!","weixin_45644430","$$$$","#######"};

    for(auto str : strings)     //1
        str += "---";

    for(auto str : strings)    //2
        cout << str << endl;
}

在注释1所在的循环中,我们对str进行了修改,让它添加了后缀"—",然后在注释2所在的循环当中,我们遍历并输出str,结果我们发现strings数组中的字符串并没有被改变。
正如我之前所说,程序会遍历strings数组当中的每一个string实例,然后将它赋值给str,然后我们修改str,实际上修改的是strings数组中的字符串的一个拷贝,strings数组中的字符串并没有被修改。想要修改strings数组当中的字符串,我们需要将str改为引用,如下所示:

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

int main ()
{
    string strings[5]{"hello world!","hello C++11!","weixin_45644430","$$$$","#######"};

    for(auto & str : strings)      //1
        str += "---";

    for(const auto & str : strings)   //2
        cout << str << endl;
}

在注释1处,我们将str改为了引用,使得我们可以直接修改strings当中的字符串,在注释2处,我们输出修改后的字符串,这里我们不对strings中的字符串进行改动,因此我们将引用声明为const。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值