官术网_书友最值得收藏!

第3章 auto占位符(C++11~C++17)

3.1 重新定義的auto關鍵字

嚴格來說auto并不是一個新的關鍵字,因為它從C++98標準開始就已經存在了。當時auto是用來聲明自動變量的,簡單地說,就是擁有自動生命期的變量,顯然這是多余的,現在我們幾乎不會使用它。于是C++11標準賦予了auto新的含義:聲明變量時根據初始化表達式自動推斷該變量的類型、聲明函數時函數返回值的占位符。例如:

auto i = 5;                      // 推斷為int
auto str = "hello auto";         // 推斷為const char*
auto sum(int a1, int a2)->int    // 返回類型后置,auto為返回值占位符
{
    return a1+a2;
}

在上面的代碼中,我們不需要為istr去聲明具體的類型,auto要求編譯器自動完成變量類型的推導工作。sum函數中的auto是一個返回值占位符,真正的返回值類型是intsum函數聲明采用了函數返回類型后置的方法,該方法主要用于函數模板的返回值推導(見第5章)。注意,auto占位符會讓編譯器去推導變量類型,如果我們編寫的代碼讓編譯器無法進行推導,那么使用auto會導致編譯失敗,例如:

auto i;    // 編譯失敗
i = 5;

很明顯,以上代碼在聲明變量時沒有對變量進行初始化,這使編譯器無法確認其具體類型要導致編譯錯誤,所以在使用auto占位符聲明變量的時候必須初始化變量。進一步來說,有4點需要引起注意。

1.當用一個auto關鍵字聲明多個變量的時候,編譯器遵從由左往右的推導規則,以最左邊的表達式推斷auto的具體類型:

int n = 5;
auto *pn = &n, m = 10;

在上面的代碼中,因為&n類型為int *,所以pn的類型被推導為int *auto被推導為int,于是m被聲明為int類型,可以編譯成功。但是如果寫成下面的代碼,將無法通過編譯:

int n = 5;
auto *pn = &n, m = 10.0;  // 編譯失敗,聲明類型不統一

上面兩段代碼唯一的區別在于賦值m的是浮點數,這和auto推導類型不匹配,所以編譯器通常會給予一條“in a declarator-list 'auto' must always deduce to the same type”報錯信息。細心的讀者可能會注意到,如果將賦值代碼替換為int m = 10.0;,則編譯器會進行縮窄轉換,最終結果可能會在給出一條警告信息后編譯成功,而在使用auto聲明變量的情況下編譯器是直接報錯的。

2.當使用條件表達式初始化auto聲明的變量時,編譯器總是使用表達能力更強的類型:

auto i = true ? 5 : 8.0;    // i的數據類型為double

在上面的代碼中,雖然能夠確定表達式返回的是int類型,但是i的類型依舊會被推導為表達能力更強的類型double

3.雖然C++11標準已經支持在聲明成員變量時初始化(見第8章),但是auto卻無法在這種情況下聲明非靜態成員變量:

struct sometype {
    auto i = 5;    // 錯誤,無法編譯通過
};

在C++11中靜態成員變量是可以用auto聲明并且初始化的,不過前提是auto必須使用const限定符:

struct sometype {
    static const auto i = 5;
};

遺憾的是,const限定符會導致i常量化,顯然這不是我們想要的結果。幸運的是,在C++17標準中,對于靜態成員變量,auto可以在沒有const的情況下使用,例如:

struct sometype {
    static inline auto i = 5;    // C++17
};

4.按照C++20之前的標準,無法在函數形參列表中使用auto聲明形參(注意,在C++14中,auto可以為lambda表達式聲明形參):

void echo(auto str) {…} // C++20之前編譯失敗,C++20編譯成功

另外,auto也可以和new關鍵字結合。當然,我們通常不會這么用,例如:

auto i = new auto(5);
auto* j = new auto(5);

這種用法比較有趣,編譯器實際上進行了兩次推導,第一次是auto(5)auto被推導為int類型,于是new int的類型為int *,再通過int *推導ij的類型。我不建議像上面這樣使用auto,因為它會破壞代碼的可讀性。在后面的內容中,我們將討論應該在什么時候避免使用auto關鍵字。

主站蜘蛛池模板: 浏阳市| 上犹县| 白水县| 阿勒泰市| 玉溪市| 长岛县| 兴仁县| 安多县| 兴安盟| 清远市| 临夏市| 台湾省| 西丰县| 富裕县| 娄烦县| 郸城县| 永州市| 常宁市| 格尔木市| 霍城县| 乌恰县| 巴青县| 河北省| 象州县| 兴义市| 克东县| 乐亭县| 百色市| 万全县| 神木县| 双流县| 绍兴市| 本溪| 中江县| 鹤岗市| 旬邑县| 花垣县| 定南县| 班戈县| 马边| 静安区|