C++11新增语法(糖)

Posted OshynSong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11新增语法(糖)相关的知识,希望对你有一定的参考价值。

新增类型

long long

C++11标准中新加入了long long类型属性,占用空间不小于long类型。

long large = LONG_MAX;
long long long_large = LLONG_MAX;
long long long_long_large = 1LL << 63;
cout<<"test long long:"<<large<<'\\t'<<long_large<<'\\t'<<long_long_large<<endl;

测试结果显示long long与long类型均为64bit。

nullptr字面量

新增这个关键字用来初始化一个空指针,可以用来转换为其他任何类型的指针,这个关键字用来替代以前的字面值0NULL两种初始化空指针的方式。

类型相关

auto类型推断

auto关键字,可以让编译器帮我们分析表达式的类型,类似模版形参推断。
需要注意的是:

  • 使用auto定义的变量必须有初始值,不然无法进行类型推断
  • 在同一条语句中使用auto定义的变量,其基础类型必须一致
double val1 = 1.1, val2 = 2.2;
auto sum = val1 + val2;
auto val3 = 0.3, *p = &val3;

double val6 = 1.6, &rval6 = val6;
auto aval6 = rval6;
aval6 = 6.0; // aval6 is not a reference.
  • 顶层const,指的是当前的数据类型本身是常量,如double,int或者相关的指针本身是常量
  • 底层const,指的是如指针、引用等复合类型,其所指向的数据类型是常量

auto在进行类型推断时,一般会忽略顶层const(top-level const),而保留底层const(low-level const)。如果想要保留顶层const,则必须显式的在auto前添加const指示符。

const int ci = 1, &cr = ci;
auto b = ci; //b是一个整数,忽略顶层const
auto c = cr; //c是int类型,cr是ci的别名,具有的顶层const忽略了
auto d = &ci; //d是一个指向整形常量的指针

auto &e = ci; //e是一个绑定到ci整形常量的引用
const auto &f = 12; //f是一个整形常量引用,绑定到常量字母量,auto &g = 12是错误的

decltype声明类型

decltype(expr)可以获得expr表达式对应的类型,并且不会对expr具体求值。

int d()

    cout<<"This function shouldn't be called."<<endl;
    return 17;

decltype(d()) dval17 = 15.2;

上述例子不会调用函数,而只会使用返回类型声明变量。
处理const时,与auto不同:

  • 如果decltype中的表达式是一个变量,那么返回该变量的类型(包括顶层const和引用在内),如果变量本身是引用就返回引用类型,否则本身不是引用时,加上括号之后结果永远是引用。
  • 如果decltype中的表达式不是变量,则返回该表达式结果对应的类型。
const int ci = 0, &cj = ci;
decltype(ci) x = 0;  //x 类型是 const int,保留了顶层const
decltype(cj) y = x;  //y 的类型是 const int &,此处是唯一的引用不是与所引用的变量的同义词出现的地方。

int i = 42, *p = &i, &r = i;
decltype(r + 0) b; //b 是一个int类型未初始化的变量,因为r+0表达式不是引用类型
decltype(r) c; //错误,c是int & 类型,必须初始化
decltype(*p) d; //错误,d是int & 类型,必须初始化,解引用运算符返回的类型是引用类型
decltype((i)) e; //错误,e是int & 类型,必须初始化,加上括号后的变量是一个表达式,编译器理解为一个引用

用途:
使用 decltype 简化函数返回类型
如果我们已经知道某个函数会返回什么对象,然而这个对象又是一个类型复杂不好写的对象,那么decltype就可以派上用场了。

int odd[] = 1, 3, 5, 7, 9;
int even[] = 0, 2, 4, 6, 8;
decltype(odd) *get_odd_or_even(int i)

    return (i % 2) ? &odd : &even;

auto val26 = get_odd_or_even(1);
cout<<"test decltype to simplify func return type:\\n";
for(auto p = begin(*val26); p != end(*val26); p++)

    cout<<p<<' '<<*p<<'\\t';

cout<<endl;

类型别名using

传统方法可以使用typedef定义类型别名,新增了using用法进行别名声明:

using array2d = vector<vector<int>>;

常量表达式constexpr

新增constexpr用于声明常量表达式,编译器会验证此变量的值是否是一个常量表达式。
常量表达式是指值不会改变,而且编译过程就能得到计算结果的表达式。字面值属于一种常量表达式,另一种就是使用const关键字声明的对象(需要用常量表达式进行初始化)。

const int a = 100;
const int b = a + 1;

//以下不是常量表达式
int c = 123; //非const限定
const int d = get_size(); //const限定d不能修改,但编译期间不能计算得到d的值

字面值包括基本数据类型、指针、引用,但指针和引用取决于初始化的值。指针必须初始化为nullptr或者是指向const对象,引用必须是绑定到const对象。函数内部的非静态变量不能使用constexpr,因为其地址不固定,静态类型可以使用constexpr指针和引用。
constexpr指针仅对指针有效是一个常量指针,等价于顶层const,与指针所指对象无关:

// a const pointer point to an int,等价于int *const p = nullptr。p可以常量也可以指向非常量
constexpr int *p = nullptr; 

// pp是一个指向const int类型的const指针,等价于const int *const pp = nullptr;
constexpr const int *pp = nullptr;

新增允许定义特殊的constexpr限定的函数,可以用这种函数初始化constexpr表达式。这种函数足以简单,使得编译期间可以计算其结果。
constexpr函数是能用于常量表达式的函数,它遵循以下几条约定:
a.返回类型是字面值类型
b.形参类型是字面值类型
c.函数体中必须有且仅有一条return语句

constexpr int sz()  return 42; 
constexpr int new_sz(int cnt)  return sz() * cnt; 
constexpr int size = sz();
constexpr int nsize = new_sz(mf);

一般如果认定变量为常量表达式,就声明为constexpr类型

语法增强

noexcept

noexcept可以用作异常指示符,用于指示一个函数是否会抛出异常。编译器并不检查使用了noexcept的函数是否真的不抛出异常,在运行时,如果一个使用noexcept承诺不抛出异常的函数实际抛出了异常,那么程序会直接终止。

void no_except() noexcept

    throw 1;

// the following call will cause terminate
//no_except();

noexcept还可以带参数,noexcept(true)表示不会抛出异常,noexcept(false)表示可能抛出异常。
同时noexcept还可以用作运算符,接受一个函数调用,返回一个bool值表示是否会抛出异常。noexcept运算符并不会对其实参进行求值。
将noexcept运算符,结合带参数的noexcept指示符,可以得到如下常用法:

void no_except2() noexcept(noexcept(no_except()))
cout<<"test noexcept: "<<noexcept(no_except())<<'\\t'<<noexcept(no_except2())<<endl;

这种用法表示no_except2no_except的异常说明保持一致。

列表初始化

可以用列表快速初始化一个容器:

// vector/list list initialization
vector<string> v1 = "ab", "cd", "ef";
list<string> l2"gh", "ij", "kl";
//vector<string> v3("mn", "op", "qr"); // wrong initialization format
cout<<"test vector/list list initialization:\\n"<<v1[1]<<'\\t'<<l2.front()<<endl;

// map/set list initialization
map<string, string> m1 =

    "a", "A",
    "b", "B",
    "c", "C"
;
m1.insert("d", "D");
set<string> s1 = "a", "b", "c";

可以在使用new动态分配内存时使用列表初始化。

vector<int> *pv = new vector<int>0, 1, 2, 3, 4;
int *pi = new int[5]0, 1, 2, 3, 4;
cout<<"test new alloator using list initialization:\\n"<<(*pv)[2]<<'\\t'<<pi[2]<<endl;

可以在传入参数/函数返回值时使用列表初始化。

vector<string> error_msg(int typ)

    switch(typ)
    
        case 1:
            return "type1", "msg1";
        case 2:
            return "type2", "msg2";
        default:
            return ;
    


pair<string, string> get_pair(int typ)

    if(typ == 1) return "key", "value";
    return pair<string, string>("default key", "default value");

以上是关于C++11新增语法(糖)的主要内容,如果未能解决你的问题,请参考以下文章

Java 语法糖详解

2020-2-2 语法糖

C# 11 预览,又增加了实用的语法糖

随笔分类 - [C#6] 新增特性

Java基础Java中的语法糖

Vue.js语法糖整理