C++0x: auto 和 decltype

| | 0 Comments| 09:51
Categories:

在上一篇的《C 語法再加強:C 0x》中,有列出在 Visual C 2010 中所新增的六項 C 0x Core Language 的新功能,也大概針對了各項也做了極為簡單的說明;而這一篇,就先來講 auto 和 decltype 這兩項新功能吧∼

auto keyword

首先,auto 這個 ketword 其實在 VC 2010 前是有其他用處的;他是所謂的「storage-class specifier」,是用來告訴編譯器一個物件或函式的週期和可見範圍、同時也告訴編譯器他應該如何被儲存。而這一類的 specifier 包括了 auto、extern、mutable、register、static 這五種,不過由於這不是本文的重點,所以就不多花時間說明了。

在 C 0x 裡,auto 這個 keyword,是用來取代直接用特定的型別(type)來宣告變數,而變數的型別則會根據所給的 initialization expression 來推導;它的形式是:

auto declarator initializer;

最簡單的例子大概如下:

int j = 0;  // j is explicitly type int.
auto k = 0; // k is implicitly type int.

上面這樣的程式,由於 0 是一個整數,所以用 auto 宣告的變數 k 的型別也會和 j 一樣、是 int。

而使用 auto 的好處呢?他主要的優點是可以讓複雜的類別有更簡單的宣告方法;尤其像有使用 template 時,要宣告變數往往要打很長一串,現在用 auto 可以代替這一長串的型別。例如下面的例子,兩行的寫法是等價的,但是用 auto 的話程式會簡短許多。

map<int,list<string>>::iterator i = m.begin(); 
auto i = m.begin(); 

同時,auto 也可以用來宣告變數、以儲存 lambda expression 這種匿名函式(anonymous function),或是用來宣告一個 function pointer 的變數。而如果把 auto 和 decltype 這個 type specifier 一起使用的話,還可以用來簡化 template 函式的開發。

不過在使用 auto 時, 需要注意到的是,由於他是根據 initialization expression 來判斷型別,所以和一般的變數宣告還是有些不同;下面是一些要注意的:

  • 使用時一定要有 initializer,下面是簡單的例子:
    auto x = 10; // ok
    auto x;      // error! without initializer
  • auto 不能用來宣告陣列、也不能用來宣告變數的 return type、函式或 template 的參數。例如下面幾個例子都是錯誤的使用方式:
    auto a[5];
    auto f(){};
    void f(auto j){};
    template<auto T> class C{};
    vector<auto> c;

這邊只是稍微列舉一些,而在 MSDN Library 的《auto Keyword (Type Deduction) 》一文中的「Restrictions and Error Messages」部分,有以可能的編譯錯誤為導向列出的完整列表,有興趣的可以參考看看。

decltype Type Specifier

decltype 這個 type specifier 是用來根據所給的 expression 決定型別,它的形式是:

decltype( expression )

他最簡單的例子,應該就是類似下面這樣的程式:

int a;
decltype( a ) b;

如此,可以宣告出一個型別和 a 一樣是 int 的 b。

而 decltype 最主要的用處,是用來和 auto 一起使用,來簡化 template 函式的開發。

auto decltype

前面一直有提到,當把 auto 和 decltype 合併使用時,可以用來簡化部分的 template 函式的撰寫。而在實作上,這是使用名為「trailing-return-type」(或稱「late-specified return type」)的特殊函示宣告方法來做到的∼下面是這種用法的基本形式:

auto function_name( parameters ) ?> decltype( expression )
{
  function_body;
}

可以發現,他這邊的 return type 是 auto、同時在 function name 後面又加上了「-> decltype( expression )」,這是透過 decltype 做判斷,告訴編譯器 auto 的型別到底是什麼;這種用來指定 retrun type 的寫法,和在使用 lambda expression 時是類似的。

這樣的寫法有什麼好處呢?透過這樣的機制,程式開發者可以寫出更有彈性的 template 函式,用來套用在不同的狀況下∼像以下方的例子來說,由於 T 和 U 相加可能會產生不同的型別,而本來的寫法會需要考慮到這個需要回傳的型別;但是使用 auto 加 decltype 的話,就可以讓編譯器自己去判斷要回傳的型別了∼

template<typename T, typename U>
auto myFunc( T& t, U& u)-> decltype( t   u ){
  return t   u;
}; 

不過說實話,Heresy 自己也還不知道這樣的功能可以用在什麼地方?本來剛看到的時候是有想到一些地方可能可以用上,但是實際玩了一下卻都發現會踩到一些限制而無法使用,總覺得似乎沒想像中的方便?不過也或許是還沒碰到需要、符合這種功能的例子吧?

參考資料:

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *