- 現代C++語言核心特性解析
- 謝丙堃
- 12字
- 2021-09-27 17:49:50
第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;
}
在上面的代碼中,我們不需要為i
和str
去聲明具體的類型,auto
要求編譯器自動完成變量類型的推導工作。sum
函數中的auto
是一個返回值占位符,真正的返回值類型是int
,sum
函數聲明采用了函數返回類型后置的方法,該方法主要用于函數模板的返回值推導(見第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 *
推導i
和j
的類型。我不建議像上面這樣使用auto
,因為它會破壞代碼的可讀性。在后面的內容中,我們將討論應該在什么時候避免使用auto
關鍵字。
- Extending Jenkins
- Learning Cython Programming(Second Edition)
- Mastering Ubuntu Server
- PHP 編程從入門到實踐
- Building Serverless Applications with Python
- SQL Server與JSP動態網站開發
- 執劍而舞:用代碼創作藝術
- Java高并發核心編程(卷1):NIO、Netty、Redis、ZooKeeper
- C專家編程
- OpenCV with Python By Example
- Extending Unity with Editor Scripting
- C陷阱與缺陷
- Elasticsearch搜索引擎構建入門與實戰
- Extending Docker
- 用Go語言自制編譯器