11.26 C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

隨著計算機性能的持續提升,編程語言似乎迎來了一次大爆發,各種編程語言不斷出現,樂意折騰的人總能找到一門適合自己胃口的編程語言。

C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

總能找到一門適合自己胃口的編程語言

程序員的口味大體可以分為兩種:一是追求極致程序效率,一是追求極致開發效率。拋開稍顯晦澀的彙編語言不談,前者以C語言程序員為代表,C語言語法簡單,可控性強,更貼近機器,適合開發超高效率的程序。後者則以各種偏腳本化的語言程序員為代表,這類編程語言更貼近人類,因此開發效率很高。

Python程序中變量的類型

下面是一段 Python 代碼,可以看出,Python 程序員在定義變量時,甚至無需關心變量的類型,只需寫出核心邏輯即可:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

counter = 100 # 賦值整型變量
miles = 1000.0 # 浮點型
name = "John" # 字符串

不過,程序中變量的數據類型本質上是用於告訴計算機其佔用內存的大小,以及該如何解釋這段數據的。所以,即使是 Python 程序,在運行時也需要確定變量的類型,否則計算機就不知道如何存儲和解釋程序中的變量。當然了,由於上面這段代碼沒有顯式的指定變量類型,所以確定數據類型的工作只能交給編譯器(或者說解釋器)了。

C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

Python使用變量非常簡單

C++程序中變量的類型

不要小看 Python 的這個特性,這可以省去相當多的“鍵盤敲擊次數”。作為實例,可以參考下面這段C++程序片段:

...
std::list<tracking> cars_list;
...
std::list<tracking>::iterator it;
for (it=cars_list.begin(); it!=cars_list.end(); it++) {
...
}/<tracking>/<tracking>
C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

這個“定義”過程需要敲擊相當多的字符

為了遍歷 list 中的元素,上述C++代碼定義了迭代器it,可以看出,這個“定義”過程需要敲擊相當多的字符:“std::list<tracking>::iterator ”。若是C++也允許像Python那樣,無需顯式的指定變量類型,而是把變量類型的確認工作交給編譯器,代碼就簡潔許多了:/<tracking>

...
std::list<tracking> cars_list;
...
for (it=cars_list.begin(); it!=cars_list.end(); it++) {
...
}/<tracking>
C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

代碼簡潔許多

這樣的C++代碼並不影響閱讀,熟悉 list 的程序員一眼就能看出it是一個迭代器。

可能有讀者覺得將“確認變量類型”的工作交給編譯器會降低編譯效率,但是其實仔細想一下,應該並非如此,請看下面這段C++代碼:

int a = 0;
int *p = &a;
a = p;

編譯器在處理第三行代碼時,大都會報錯,給出類似於下面這樣的信息:

error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]

這說明C++編譯器在處理變量賦值時,也需要確定右值的類型,因此從理論上來看,自動推導類型並不會帶來多少額外的工作。

C++中的auto關鍵字

事實上,C++11標準的確增加了“變量類型自動推導”的功能,只不過不像 Python,C++的這一功能需要藉助auto關鍵字。

其實早在C++98標準中,就已經存在auto關鍵字了,只不過那時的auto關鍵字僅用於聲明變量擁有自動的生命週期,可是不使用 auto 關鍵字定義的變量仍然具有自動的生命週期,所以那時的 auto 關鍵字屬於多餘的特性。

C++11標準丟棄了auto關鍵字之前的特性,取而代之的,將此關鍵字用於定義“可自動推導類型”的變量。下面是一段C++代碼示例,請看:

int a = 8;
auto b = a; // 自動推導 b 的類型為 int
cout << typeid(b).name() << endl;
C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

自動推導類型的C++代碼示例

編譯這段C++代碼時應注意指定C++11標準:

# g++ t.cpp -std=c++11
# ./a.out
i

可見,程序輸出了i,表示變量 b 為 int 類型,這說明auto關鍵字的確根據 b 的右值(int型的a)確定了 b 的類型為 int。

現在有了auto關鍵字,前面那個遍歷 list 的C++代碼片段就可以改寫了,請看:

for (std::list<tracking>::iterator it=cars_list.begin(); it!=cars_list.end(); it++){
...
}
// 現在可以改寫為
for (auto it=cars_list.begin(); it!=cars_list.end(); it++){
...
}/<tracking>
C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

顯然簡潔了許多

顯然簡潔了許多,C++程序員也可以少敲很多次鍵盤,手指健康得到了一定程度的保護。

C++的 auto 關鍵字用於模板

上面只是C++中 auto 關鍵字的其中一種用法,事實上,auto 關鍵字不僅僅能夠讓程序員少敲代碼,也能帶來一些功能上的便利。例如,在定義模板函數時,用於聲明依賴模板參數的變量類型,下面是一段C++代碼示例:

template <typename>
void add(_Tx x, _Ty y)
{
auto v = x+y;
std::cout << v;
}/<typename>

請注意變量 v 的定義,如果這裡不使用 auto 關鍵字就棘手多了,因為我們根本無法事先確定變量 x 和 y 的類型,不到編譯的時候,誰能知道 x+y 的結果究竟是什麼類型呢?

C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

誰能知道 x+y 的結果究竟是什麼類型呢?

讀者應該注意到上面的 add() 函數其實並不好用,因為它沒有將結果返回給調用者。於是可以做如下修改,請看相關C++代碼:

template <typename>
auto add(_Tx x, _Ty y)
{
return x+y;
}/<typename>

可見,auto 關鍵字也可用於自動推導模板函數的返回值類型,否則 add() 函數的返回值類型也是相當難確定的。不過,在編譯這段C++代碼時,發現如下警告信息:

warning: ‘add’ function uses ‘auto’ type specifier without trailing return type [enabled by default]
auto add(_Tx x, _Ty y)

要避免出現這樣的警告信息,可以使用C++11標準引入的新關鍵字decltype,相關的C++代碼如下,請看:

template <typename>
auto add(_Tx x, _Ty y)->decltype(x+y)
{
return x+y;
}/<typename>
C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

auto用於定義模板函數

auto 在這裡的作用也稱為返回值佔位,它只是為函數返回值佔了一個位置,真正的返回值是後面的decltype(x+y)。現在編譯這段C++代碼,可以得到如下輸出,請看:

# g++ t.cpp -std=c++11
# ./a.out
9.14
7
145

注意事項

auto 關鍵字的“自動推導類型”功能是由編譯器提供的,而編譯器也不是占卜得到變量類型的,它需要知道一些信息,因此 auto 在定義變量時必須初始化:

int i = 3;
auto j = i;

只有這樣,編譯器才能根據右值的類型推導出 auto 變量的類型。也正是因為如此,auto 變量作為函數的參數是非法的:

// 非法
void foo(auto a){
...
}

若是使用 auto 關鍵字在同一行定義多個變量,這些變量必須是同一類型,否則編譯器就會報錯,例如下面這兩行C++代碼:

auto a1 = 1, a2 = 2;//正確
auto b1 = 10, b2 = 'a';//錯誤,沒有推導為同一類型

如果 auto 變量初始化時的右值為引用,則去除引用。請看下面這段C++代碼:

int a = 1;
int &b = a;

auto c = b; // 此時 c 的類型為 int

c = 100; // a 依然為 1

如果希望自動推導為引用類型,則需要配合&運算符:

auto &d = b;
d = 100; // 此時 a 為 100

類似的,如果初始化表達式帶有 const 或者 volatile 修飾符,僅有 auto 定義的變量去除 const 和 volatile 修飾符。

最後要說明的是,C++中的 auto 關鍵字並不是真正的類型,它僅用於告訴編譯器“應該自動推導變量的類型”,所以像 sizeof() 以及 typeid() 這樣操作數據類型的操作符是不能用於 auto 的,下面這兩行C++代碼是非法的:

size = sizeof(auto); // 非法
cout << typeid(auto).name() << endl; // 非法

小結

本節主要討論了C++11標準中的 auto 關鍵字,可見,它不僅能夠讓程序員少敲鍵盤,提升了C++程序開發效率,還額外提供了一些功能上的便利。文章在最後還討論了使用 auto 關鍵字的注意事項,希望對讀者有所幫助。

C++也能像其他編程語言那樣,讓編譯器自動推導變量類型嗎?

點個關注吧

歡迎在評論區一起討論,質疑。文章都是手打原創,每天最淺顯的介紹C語言、linux等嵌入式開發,喜歡我的文章就關注一波吧,可以看到最新更新和之前的文章哦。


分享到:


相關文章: