C++0x:static_assert 和 nullptr

| | 0 Comments| 15:37
Categories:

之前已經介紹了 C 0xauto、decltypeLambda expression 了∼而這一篇,則是繼續介紹一下 static_assert 和 nullptr 這兩項。

static_assert

static_assert 基本上是用來讓編譯器在編譯階段產生錯誤,並輸出給定的錯誤訊息的 declaration;他可以判斷給定的 constant expression,在不符合條件的情況下,就讓編譯器編譯失敗,產生錯誤訊息。他的形式很簡單,就是:

static_assert( constant-expression, string-literal );

static_assert 在 constant-expression 為 true(或非 0)的時候,完全不會有任何反應,但是如果是 false(或 0)的時候,就會讓編譯器編譯失敗,將 string-literal 當作錯誤訊息顯示出來。

這樣可以怎麼使用呢?主要就是拿來做一些編譯階段就可以做的判斷了∼例如在 MSDN 上給的一個例子就是用來判斷編譯器是否能夠支援 64-bit:

static_assert(
  sizeof(void *)==4,
  "64-bit code generation is not supported.");

另外在 Visual C Team Blog 的《Lambdas, auto, and static_assert: C 0x Features in VC10, Part 1》一文中,也有一個用來針對 template struct 做參數確認的例子:

template <int N> struct Kitten {
  static_assert(N < 2, "Kitten<N> requires N < 2.");
};

透過這樣的寫法,可以限制 Kitten 這個 template struct 的參數 N 需要小於 2,如果遇到不符合的情況下,會直接無法編譯。

在 Heresy 來看,static_assert 應該是比較適合用在函示庫的開發上;透過使用 static_assert,可以直接在編譯階段就針對使用這個函示庫的程式做檢查,如果有問題就直接透過編譯錯誤的訊息來告訴開發者,而不需要在 run-time 再來做確認。

另外,在 open-std 的文件裡,還有許多其他例子可以參考,有興趣的話可以參考看看。

nullptr

nullptr 這個特殊的常數,是用來代表指標沒有指向任何東西用的。

在以往的 C / C 裡,要將指標設定不指向任何東西,都是將他的值設定為 0(NULL 實際上也只是定義為 0 的 macro)就結束了。這樣有什麼缺點的?主要就是 null pointer 和 0 之間在某些狀況下會產生混淆、無法分辨了∼假設現在有兩個函式:

void f(int){ printf( "int" ); }
void f(char*){ printf( "char*" ); }

而在這種情況下,如果用下面四種方法呼叫的話,會分別得到不同的結果:

f( NULL );     // int, compile error in GCC
f( 0 );        // int
f( (char*)0 ); // char*
f( (void*)0 ); // compile error

也就是說,除非透過 explicit cast 的方式強制把 0 轉型成 char*(上方第三行的寫法),不然是沒辦法呼叫到 f(char*) 的。

而 nullptr 就是為了解決這樣的問題而制定出來的一個新的特別常數,型別應該是「nullptr_t」;由於他純粹就代表一個沒有指到任何東西的指標,型別也不是 int,所以就不會和 0 有所衝突了!也就是說,現在呼叫 f( nullptr ); 就可以呼叫到 f(char*) 了∼

不過,要使用 nullptr 的話,還有一些地方是和使用現有的 NULL 不同的地方,像是:

  • nullptr 不能轉型成 boolean 變數,所以不能使用 if( nullptr ){…} 這樣的寫法。
  • nullptr 不是數值,所以不能用來指定成 int 的值,例如 int n = nullptr; 就是錯誤的寫法;另外他也不能用來和 int 做比較,例如 下面的寫法也是無法正確編譯的:
    int n2 = 0;
    if( n2 == nullptr )
    {...}

另外,下面也還有一些更進階的使用例子:

template<typename T> void g( T* t );
g( nullptr );          // error
g( (float*)nullptr ); // deduces T = float
 
template<typename T> void h( T t );
h( 0 );               // deduces T = int
h( nullptr );         // deduces T = nullptr_t
h( (float*)nullptr ); // deduces T = float*

其他細節可以參考 Open STD 的《A name for the null pointer: nullptr》一文。

Leave a Reply

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