C++11特性總結(1)-decltype、類內初始化、列表初始化返回值

decltype

做用:返回表達式或變量的類型c++

返回值規則:程序員

  • 若e是一個左值(lvalue,即「可尋址值」),則decltype(e)將返回T&
  • 若e是一個臨終值(xvalue),則返回值爲T&&
  • 若e是一個純右值(prvalue),則返回值爲T

decltype()不會執行括號內的表達式,decltype返回的類型是用於聲明的,不能用於單純的判斷。 好比decltype(a)==int,是不能夠的,只能是在定義新的變量、返回值的地方使用:編程

int a=1;
decltype(a) b  (等價於int b)
複製代碼

如果給變量加多了1個括號,則會成爲一個表達式。bash

int a = 1;
int b=2;
decltype((a))  d=b // decltype((a)) 返回類型int&。而引用必須賦初值,因此這裏的d必須賦初值。
複製代碼

若表達式和指針相關的用法:函數

設p是指向int變量的指針ui

  1. decltype(*p)-》返回int& 即引用
  2. decltype(p)-》返回int* 即指針
  3. decltype(&p)-》返回int** 即指針的指針。

這裏解釋一下爲何1返回的是引用而不是int:由於*p返回的本質上就是一個引用,當咱們向*p賦值的時候,改變的是變量本來的值,而不是作了一個拷貝,顯然這是引用的性質。spa

泛型編程中使用decltype:指針

經過和尾置返回類型結合,可使得返回值能夠由編譯器推斷,無需程序員指出。主要用於編寫轉發函數c++11

int& foo(int& i);
float foo(float& f);

template <class T> 
auto transparent_forwarder(T& t) −> decltype(foo(t)) 
{
    return foo(t);
}
複製代碼

像這個例子若是沒有decltype,咱們沒法肯定foo(t)究竟是兩個備選函數中的哪個,由於這是在運行時決定的。這樣子咱們沒法直接編寫transparent_forwarder函數的返回值。code

還有其餘不少例子,decltype經常使用於難以肯定變量類型的地方,而模板就是爲了適配多類型而產生的,因此在泛型編程中,不少時候都會用到decltype來作到靈活定義變量類型。

類內初始化

C++11之前是不能夠在一個類的數據成員聲明的時候初始化的,除非是一個const的靜態變量:

class A
{
    static int i = 1; //correct,不得不在此賦值,由於const常量必須在聲明時賦值
    int num=2; //error,不容許在類內聲明的時候對數據成員初始化
};
複製代碼

這樣子帶來繁瑣的問題就是:儘管咱們只是想爲全部該類的實例的數據成員都設置一個初始值,也必須本身定義一個構造函數才能作到。

因而在c++11: 容許直接在類內初始化值(前提:這個值必須是常量表達式)。

順序:類內部初始化先於構造函數初始化進行,構造函數初始化會覆蓋類內部初始化。也就是說,若是咱們即定義了類內初始化值,又定義了本身的構造函數,最終的結果仍是按照咱們的意願,對數據成員按照構造函數賦值。

使用方法:

class A
{
    int num=2; //correct,C++11容許在類內聲明的時候對數據成員初始化
    int a{7}  //用花括號賦值也能夠,a=7    
};
複製代碼

注意:C++11中,仍然沒有改變靜態數據成員必須在類內聲明,類外初始化的事實。

class A
{
    static int d = 1; //error
};
int A::d = 1 //correct,通常來講:初始化語句會放在cpp文件,類定義放在h文件
複製代碼

列表初始化返回值

在C++11以前,若是咱們想要返回一組數據,咱們必須在子函數中構造一個對應的容器,藉助容器來進行返回。

vector<int> process()
{
    vector<int> v={1,2,3,4}
    return v;
}
複製代碼

在新標準下,咱們能夠直接返回字面值,該字面值會用於容器的構造,而無需咱們本身去構造。

vector<int> process()
{
    return {1,2,3,4};
}
複製代碼
相關文章
相關標籤/搜索