【C++ grammar】Enhancement for Type System (C++11 對型別系統的增強)
資料型別 (Data type)
int, long int, double, struct, char *, float [], int (*f)()…
計算機程式構造塊
計算機程式構造塊是不同大小粒度的計算機程式組成部分,它包括變數、表示式、函式或者模組等。
型別系統 (Type System)
型別系統:在程式語言中,“型別系統”是將“type”屬性指定給不同計算機程式構造塊的規則集
為什麼使用型別系統:減少程式中可能出現的bug
1、定義不同程式塊之間的介面
2、檢查多個塊之間是否以一致的方式連線在一起
型別系統分為:靜態型別和動態型別
型別系統存在於我們編寫程式中,編譯器會幫我們檢查型別系統。
如果檢查發生在編譯期(編譯的時候檢查型別系統是否一致),稱為靜態型別
如果檢查發生在執行期(執行的時候檢查型別系統是否一致),稱為動態型別
如果檢查同時存在與編譯期間和執行期間,稱為混合型別
C、C++、Java是靜態型別
Python是動態型別
Automatic Type Deduction: auto (C++11) 自動型別推導:auto關鍵字
C++03及之前的標準種,auto放在變數宣告之前,宣告變數的儲存策略。但是這個關鍵字常省略不寫。
C++11中,auto關鍵字放在變數之前,作用是在宣告變數的時候根據變數初始值的型別自動為此變數選擇匹配的型別
例:
int a = 10;
auto au_a = a;//自動型別推斷,au_a為int型別
cout << typeid(au_a).name() << endl;
result:
int
注意點:
1、auto 變數必須在定義時初始化,這類似於const關鍵字
auto a1 = 10; //正確
auto b1; //錯誤,編譯器無法推導b1的型別
b1 = 10;
2、定義在一個auto序列的變數必須始終推導成同一型別
auto a4 = 10, a5{20}; //正確
auto b4{10}, b5 = 20.0; //錯誤,沒有推導為同一型別
3、如果初始化表示式是引用或const,則去除引用或const語義。
int a{10}; int &b = a;
auto c = b; //c的型別為int而非int&(去除引用)
const int a1{10};
auto b1 = a1; //b1的型別為int而非const int(去除const)
4、如果auto關鍵字帶上&號,則不去除引用或const語意
int a = 10; int& b = a;
auto& d = b;//此時d的型別才為int&
const int a2 = 10;
auto& b2 = a2;//因為auto帶上&,故不去除const,b2型別為const in
5、初始化表示式為陣列時,auto關鍵字推導型別為指標
int a3[3] = { 1, 2, 3 };
auto b3 = a3;
cout << typeid(b3).name() << endl; //輸出int * (輸出與編譯器有關)
6、若表示式為陣列且auto帶上&,則推導型別為陣列型別
int a7[3] = { 1, 2, 3 };
auto& b7 = a7;
cout << typeid(b7).name() << endl; //輸出int [3] (輸出與編譯器有關)
7、C++14中,auto可以作為函式的返回值型別和引數型別
auto max(int x , int y)
{
return x>y?x:y;
}
我們在使用auto時有時會遇到一些特殊情況。
1、 “int x = 3;” 能變成auto形式嗎?
當我們非常希望能夠在變數定義的時候,【明確】地指出變數的型別,而且不希望隨便更改其型別,那麼我們可以使用下面的方法:
auto x = int {3}; // 初始化列表
auto y = int {3.0}; // 編譯器報錯,初始化列表不能窄化
auto z = int (3.0); // C風格的強制型別轉換,z的值是整數3
2、 auto和初始化列表一起用 要避免在一行中使用直接列表初始化和拷貝列表初始化,也就是,下面的程式碼是有問題的:
auto x { 1 }, y = { 2 }; // 不要同時使用直接和拷貝列表初始化
“AAA原則”:總是使用auto!
問題:能用auto宣告C風格的陣列嗎?
如果你嘗試讓C++11編譯器編譯如下程式碼,它會報錯
// 包含標頭檔案
// 宣告主函式
// ......
auto x[] = {1,2,3};
auto 不能用於宣告陣列,否則無法通過編譯,報auto型別不能出現在頂級陣列型別中。
也就是說auto只能是指標指向陣列的而不能去宣告一個陣列。
自動型別推導:decltype關鍵字
1、關鍵字decltype的用法
decltype利用已知型別宣告新變數。
有了auto,為什麼還要整出一個decltype?原因是,我們有時候想要從表示式的型別推斷出要定義的變數型別,但不想用該表示式的值初始化變數。
decltype是在編譯期推導一個表示式的型別,而不用初始化,其語法格式有點像sizeof。它只做靜態分析,因此它不會導致已知型別表示式執行。
decltype 主要用於泛型程式設計(模板)
2、程式碼示例
#include<iostream>
using namespace std;
int fun1() { return 10; }
auto fun2() { return 'g'; } // C++14
int main(){
// Data type of x is same as return type of fun1()
// and type of y is same as return type of fun2()
decltype(fun1()) x; // 不會執行fun1()函式,相當於 int x;
decltype(fun2()) y = fun2(); //auto y=>char y;
cout << typeid(x).name() << endl;
cout << typeid(y).name() << endl;
return 0;
}
我們可以發現,我們將fun2的‘g’改變,例如改成4,y型別也改了。
這樣我們修改了返回值型別,程式仍然能夠正常執行。
這說明,使用型別推導是有好處的。
3、decltype與auto的對比
decltype和auto都是C++11自動型別推導的關鍵字。它們有很多差別:
auto忽略最上層的const,decltype則保留最上層的const
auto忽略原有型別的引用,decltype則保留原有型別的引用
對解引用操作,auto推斷出原有型別,decltype推斷出引用
4、auto推斷時會實際執行,decltype不會執行,只做分析。
總之在使用中過程中和const、引用和指標結合時需要特別小心。
小結
C++11對C++03的增強,或者說C++11的“Modern”的特點之一就是由auto和decltype構成的自動型別推導系統。
但是,auto與初始化列表結合,又有一些坑。你在寫程式碼時如果經常將auto與列表初始化一起使用,那麼會遇到一些問題。本節只介紹auto的常見用法。auto與初始化列表結合的坑,得由你自己去踩了。
為了說明auto有多麼複雜,這裡摘取 https://cppreference.com 網站列出的auto的語法格式:
相關文章
- 影像增強(Image enhancement)
- C++強制型別轉換C++型別
- TypeScript type 型別別名TypeScript型別
- drools的型別宣告(Type declarations)型別
- C C++ 強制型別轉換C++型別
- Rust的變數型別__Data typeRust變數型別
- Java中的Type型別詳解Java型別
- C++系統相關操作3 - 獲取作業系統的平臺型別C++作業系統型別
- HTTP Content-Type型別HTTP型別
- Python -型別提示 Type HintsPython型別
- 基礎篇:深入解析JAVA泛型和Type型別體系Java泛型型別
- 不用typsescript也能使用型別增強功能型別
- 全域性 type 型別的尋找 typescript 型別 - fabric.Canvas型別TypeScriptCanvas
- Pytorch框架之tensor型別轉換(type, type_as)PyTorch框架型別
- input的type值型別和描述-HTML型別HTML
- 深入學習typescript type型別TypeScript型別
- typescript type 分配條件型別TypeScript型別
- Dart 裡的型別系統Dart型別
- 基於 SVM 和增強型 PCP 特徵的和絃識別特徵
- EXT4檔案系統學習(12)VFS之檔案系統物件file_system_type物件
- go 如何擴充系統型別或者別人的型別Go型別
- TypeScript 型別系統TypeScript型別
- ERP系統型別大對比,切勿盲目選擇型別
- 理解 Swift 中的元型別:.Type 與 .selfSwift型別
- TypeScript型別系統和基礎型別TypeScript型別
- 使用增強型for迴圈(for-each)相比傳統的for迴圈有什麼區別?
- jQuery匹配指定type型別input元素jQuery型別
- <input type="file"> 限制檔案型別型別
- JavaScript新增型別語法Type SyntaxJavaScript型別
- 檢視系統型別的命令型別
- 檢視系統的SHELL型別型別
- C++11獲取double型別的最大最小值C++型別
- C#模擬C++模板特化對型別的值的支援C#C++型別
- 增強版本的自開發SAP WebClient UI Repository Information SystemWebclientUIORM
- TypeScript 強大的型別別名TypeScript型別
- C++與Rust資料型別對應關係C++Rust資料型別
- 阿里雲伺服器計算網路增強型例項和通用網路增強型例項區別?阿里伺服器
- 增強型evssl證書的作用