- C++服務器開發精髓
- 張遠龍
- 1567字
- 2021-07-23 18:22:08
1.5 C++17注解標簽(attributes)
在C++98/03時代,不同的編譯器使用不同的注解為代碼增加了一些額外的說明,讀者可能在各種C/C++代碼中見過#pragma、__declspec、__attribute等注解。然而,不同的編譯器對于同一功能可能使用不同的注解,導致我們需要為不同的編譯器編寫不同的注解代碼。從C++11開始,新的語言標準統一制定了一些常用的注解標簽,本節介紹一些比較常用的注解標簽。使用注解標簽的語法如下:

這些標簽可用于修飾任意類型、函數或者enumeration,在C++17之前不能用于修飾命名空間(namespace)和enumerator,在C++17標準中,這個限制也被取消了。
1.5.1 C++98/03的enumeration和C++11的enumerator
讀者可能對enumeration和enumerator這兩個詞感到困惑,前者指的是從C時代就存在的不限定作用域的枚舉。例如,下面的枚舉類型就是一個enumeration:

這種枚舉類型之所以被稱為不限定作用域的枚舉,是因為一旦定義了這樣一種枚舉,在其所在的作用域內就不能再定義與之同名的變量了。例如,如果定義了上述Color枚舉,此時再定義一個名為 white 的變量,就無法編譯通過了。而 enumerator 指的是從 C++11開始引入的以如下形式定義的枚舉變量:

此時,由于枚舉值white對外部不可見(必須通過Color::white引用),所以可以定義一個同名的white變量。這種枚舉變量被稱為限定作用域的枚舉。
1.5.2 C++17的注解標簽
在分清楚enumeration和enumerator之后,讓我們回到正題上來。
C++11引入的常用注解標簽有[[noreturn]],這個注解的含義是告訴編譯器某個函數沒有返回值,例如:

這個標簽一般在設計一些系統函數時使用,例如std::abort()和std::exit()。
C++14 引入了[[deprecated]]標簽來表示一個函數或者類型等已被棄用,在使用這些被棄用的函數或者類型并編譯時,編譯器會給出相應的警告,有的編譯器直接生成編譯錯誤:

這個標簽在實際開發中非常有用,尤其在設計一些庫代碼時,如果庫作者希望某個函數或者類型不想再被用戶使用,則可以使用該標注標記。當然,我們也可以使用如下語法給出編譯時的具體警告或者出錯信息:

有如下代碼:

若在main函數中調用被標記為deprecated的函數funcX,則在gcc/g++7.3中編譯時會得到如下警告信息:

Java 開發者對這個標注應該再熟悉不過了。在 Java 中使用@Deprecated 標注可以達到同樣的效果,這大概是 C++標準委員“拖欠”廣大 C++開發者太久的一個特性吧。
C++17提供了三個實用注解:[[fallthrough]]、[[nodiscard]]和[[maybe_unused]],這里逐一介紹它們的用法。
[[fallthrough]]用于 switch-case 語句中,在某個 case 分支執行完畢后如果沒有 break語句,則編譯器可能會給出一條警告。但有時這可能是開發者有意為之的。為了讓編譯器明確知道開發者的意圖,可以在需要某個 case分支被“貫穿”的地方(上一個case沒有break語句)顯式設置[[fallthrough]]標記。代碼示例如下:


注意:在gcc/g++中,[[fallthrough]]后面的分號不是必需的,在Visual Studio中必須加上分號,否則無法編譯通過。
熟悉Golang的讀者,可能對fallthrough這一語法特性非常熟悉,Golang中在switch-case后加上fallthrough,是一個常用的告訴編譯器意圖的語法規則。代碼示例如下。

[[nodiscard]]一般用于修飾函數,告訴函數調用者必須關注該函數的返回值(即不能丟棄該函數的返回值)。如果函數調用者未將該函數的返回值賦值給一個變量,則編譯器會給出一個警告。例如,假設有一個網絡連接函數 connect,我們通過返回值明確說明了連接是否建立成功,則為了防止調用者在使用時直接將該值丟棄,我們可以將該函數使用[[nodiscard]]標記:

在C++20中,對于諸如operator new()、std::allocate()等庫函數均使用了[[nodiscard]]進行標記,以強調必須使用這些函數的返回值。
在通常情況下,編譯器會對程序代碼中未使用的函數或變量給出警告,另一些編譯器干脆不允許通過編譯。在C++17之前,程序員為了消除這些未使用的變量帶來的編譯警告或者錯誤,要么修改編譯器的警告選項設置,要么定義一個類似于UNREFERENCED_PARAMETER的宏來顯式調用這些未使用的變量一次,以消除編譯警告或錯誤:

以上代碼節選自一個標準 Win32 程序的結構,其中的函數參數 hPrevInstance 和lpCmdLine一般不會被用到,編譯器會給出警告。為了消除這類警告,這里定義了一個宏UNREFERENCED_PARAMETER并進行調用,造成這兩個參數被使用的假象。
有了[[maybe_unused]]注解之后,我們就再也不需要這類宏來“欺騙”編譯器了。以上代碼使用該注解后可以修改如下:

讀者可以通過C++官網了解C++新標準中更多注解的用法。
- SpringMVC+MyBatis快速開發與項目實戰
- Raspberry Pi Networking Cookbook(Second Edition)
- C# Programming Cookbook
- C# 從入門到項目實踐(超值版)
- 微服務設計原理與架構
- PHP網絡編程學習筆記
- Microsoft System Center Orchestrator 2012 R2 Essentials
- 自然語言處理Python進階
- Visual C#.NET程序設計
- C和C++游戲趣味編程
- HTML5 APP開發從入門到精通(微課精編版)
- SQL 經典實例
- Building Microservices with .NET Core
- INSTANT Apache ServiceMix How-to
- PHP+MySQL Web應用開發教程