舉例來說,我們常常要為 STL container 宣告 iterator 時,往往會寫這樣子的程式碼:
std::map<int, std::string> myMap; ... ... std::map<int, std::string>::iterator itor = myMap.begin(); // do something with itor
其中我們的變數名稱只有四個字,而型別名稱卻有三十多字,若我們有許多這樣子的 container 及宣告,那程式碼中必然充斥著滿滿的宣告,而降低可讀性。對於這種問題,傳統的做法就是使用 typedef 或是 marco,但都只能解決一小部分的問題,就是程式碼看起來比較乾淨,但對於程式員而言,還是需要記得這冗長的型別名稱。myMap.begin( ) 回傳值的型別,你知我知 Compiler 也知,甚至在編譯期就可以確定了,那我們能夠少打這些多餘的字嗎?
C++0x 提出了兩個關鍵字來解決這問題:auto 及 decltype。
- auto 是個從 C 語言繼承而來的關鍵字,在 C++0x 之前,auto 是一種 storage-class specifiers,用來修飾變數宣告的 scope、lifetime 及 storage。如果一個變數的宣告前加上 auto 的話,那就表示是宣告一個 Local variable。如果一個變數宣告沒有加任何的 storage-class specifiers (如 static、register、extern …等),那預設就是auto。因為如此,auto 很少被使用。
// Variable i is explicitly declared auto (local variable). auto int i = 0; // Variable j is implicitly declared auto (local variable). int j = 0;
在 VC2010 及 C++0x 中,auto 有了新的作用,用來表示一個經由 compiler 推導的型別 (Deduce Variable Type)。你可以在變數宣告前加上 auto 並給予初始值,該變數的型別會根據初始值來決定。可以被推導的型別有:const、volatile、pointer、reference 及 rvalue reference。
我們可以在compile時加上參數。以選擇我們對於 auto 的使用方式:
- /Zc:auto- : 表示將auto當成舊式的 storage-class specifiers
- /Zc:auto (default): 表示將auto當成新式的 deduce variable type
// 宣告
// Variable j is explicitly type int.
int j = 0;
// Variable k is implicitly type int because 0 is an integer.
auto k = 0;
// 宣告 iterator (由其在loop裡)
deque<double> dq1(2,0.1);
for (auto it = dq1.begin(); it != dq1.end(); ++it)
{
// do something
}
for_each(auto elem in dq1)
{
// do something
}
// 宣告 pointer
double x = 12.34;
auto *y = new auto(x), **z = new auto(&x);
// More
auto x = 1, *y = &x, **z = &y; // Resolves to int.
auto a(2.01), *b (&a); // Resolves to double.
auto c = 'a', *d(&c); // Resolves to char.
auto m = 1, &n = m; // Resolves to int.
// 搭配 :? 使用
int v1 = 100, v2 = 200;
auto x = v1 > v2 ? v1 : v2;
// 搭配 const 使用
int f(int x) { return x; }
int main()
{
auto x = f(0);
const auto & y = f(1);
int (*p)(int x);
p = f;
auto fp = p;
...
} auto 雖然好用,但它並非萬能,以下為一些誤用 auto 的情況 (以下皆使用新式 auto,即 Compile with /Zc:auto )
- 不能跟其它的 type-specifier 一起使用
// error auto int x;
- 用 auto 宣告變數必需給初始值
// error auto x1; auto y1, y2, y3; auto z1 = 1, z2, z3 = -1;
- auto 不可當作函式回傳型別, 亦不可當作 array 型別
// error
auto f( ){ }
auto a[5];
auto b[1][2];
auto y[5] = x;
auto z[] = {1, 2, 3};
auto w[] = x;
- auto 不可當作參數, 或 template 參數的型別
// error
void f(auto j){}
template<class T> class C{};
int main()
{
C<auto> c; // C3539
return 0;
}
- auto 搭配 new 使用時必需有初始值
// error new auto(); auto x = new auto();
- auto 不可被推導成 void, 亦不可宣告一個 auto pointer, 卻代入一物件(或內建型別)當初始值
// error
void f(){}
auto x = f();
auto* x = 123.0;
class A { };
A x;
auto *p = x;
- 不可以該 auto 變數來自我初始化
// error auto a = a; auto b = &b; auto c = c + 1; auto* d = &d; auto& e = e;
- 不可將其它型別轉型(cast)成 auto 型別
// error auto(value); (auto)value; auto x1 = auto(value); auto x2 = (auto)value; auto x3 = static_cast<auto>(value);
- 在同一行所宣告的 auto 變數, 都必需被推導成同一型別
// error // Variable x1 is a pointer to char, // but y1 is a double. auto * x1 = "a", y1 = 3.14; // Variable c is a char, // but c1, c2, and c3 are pointers to pointers. auto c = 'a', *c1 = &c, * c2 = &c1, * c3 = &c2; // Variable x2 is an int, // but y2 is a double and z is a char. auto x2(1), y2(0.0), z = 'a'; // Variable a is a pointer to int, // but b is a pointer to double. auto *a = new auto(1), *b = new auto(2.0);
- 不可對 auto 使用 sizeof 或 typeid
auto x = 123; sizeof(x); // OK sizeof(auto); // Error auto x = 123; typeid(x); // OK typeid(auto); // Error
- decltype 是 C++0x 新增的一個關鍵字,它接受一個 expression,並由該 expression 推導出一個型別。
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1; // type is const int&&
decltype(i) x2; // type is int
decltype(a->x) x3; // type is double
decltype((a->x)) x4; // type is const double&
如今,auto 及 decltype 幾乎完全確定會制定於 C++0x當中了,但也是未來的 compiler 才會支援。這麼好用的東西,現在不能用實在是很可惜,所以 Boost 提供了兩個 marco 來模擬 auto 及 decltype。它們分別是BOOST_AUTO 及 BOOST_TYPEOF。
- BOOST_AUTO 的用法為 BOOST_AUTO( Var, Expr),它會依 Expr 推導的型別宣告一個名為 Var 的變數,並初始化為 Expr 的值。
- BOOST_TYPEOF 的用法為 BOOST_TYPEOF( Expr ),結果為一個經由推導 Expr 而成的型別指示詞 (Type specifier)。
#include <boost/typeof/typeof.hpp>
vector<string> func()
{
vector<string> v(10);
return v;
}
int main()
{
BOOST_TYPEOF(2.0*3) x = 2.0*3;
BOOST_AUTO(y, 2.3) ;
BOOST_AUTO(&a, new double[20]);
BOOST_AUTO(p, make_pair(1, "string"));
BOOST_AUTO(v, func() );
return 0;
}
參考資料:
http://msdn.microsoft.com/en-us/library/dd465215.aspx
http://www.boost.org/doc/libs/1_46_1/doc/html/typeof/tuto.html
沒有留言:
張貼留言