C++0x:static_assert 和 nullptr


之前已經介紹了 C++0xauto、decltypeLambda expression 了~而這一篇,則是繼續介紹一下 static_assertnullptr 這兩項。

static_assert

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

static_assert( constant-expression, string-literal );

static_assertconstant-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( "intn" ); }
void f(char*){ printf( "char*n" ); }

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

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》一文。

對「C++0x:static_assert 和 nullptr」的想法

  1. 你好,請問這個例子是不是有問題呢?
    static_assert(
    sizeof(void *)==4,
    “64-bit code generation is not supported."
    );
    是不是應該改成assert sizeof void* == 8 ? assert失敗時顯示這個message才正確

發表留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料