inline 指定符
inline 指定子在用於函式的 decl-specifier-seq 時,會將該函式宣告為 inline 函式 (inline function)。
完全定義在 class/struct/union 定義內部的函式,不論是成員函式或是非成員的 friend 函式,皆隱含地為 inline 函式,除非其被附加至某個具名模組(自 C++20 起)。
|
在首次宣告時即被宣告為 constexpr 或 consteval(自 C++20 起) 的函式,隱含地為 inline 函式。 被刪除 (deleted) 的函式隱含地為 inline 函式:其(已刪除的)定義可以出現在多個編譯單元(translation unit)中。 |
(C++11 起) |
|
inline 指定子在用於具靜態儲存期變數(靜態類別成員或命名空間範圍變數)的 decl-specifier-seq 時,會將該變數宣告為 inline 變數 (inline variable)。 在首次宣告時即被宣告為 constexpr 的靜態資料成員,隱含地為 inline 變數。 |
(自 C++17 起) |
目錄 |
[編輯] 說明
inline 函式或 inline 變數(自 C++17 起)具有下列性質:
- inline 函式或變數(自 C++17 起)的定義必須在存取它的編譯單元中是可達(reachable)的(不一定要在存取點之前)。
- 具有 外部連結性 (external linkage)(例如未宣告為 static)的 inline 函式或變數(自 C++17 起)具有下列額外性質:
- 程式中可以有超過一個 inline 函式或變數(自 C++17 起)的定義,只要每個定義出現在不同的編譯單元中,且(對於非靜態 inline 函式及變數(自 C++17 起))所有定義皆相同。例如,inline 函式或 inline 變數(自 C++17 起)可以定義在包含於多個原始碼檔案的標頭檔中。
- 它必須在每個編譯單元中都被宣告為 inline。
- 它在每個編譯單元中都具有相同的位址。
在 inline 函式中:
- 所有函式定義中的「函式區域靜態物件 (function-local static objects)」在所有編譯單元之間共用(它們都指向定義在一個編譯單元中的同一個物件)。
- 所有函式定義中定義的型別,在所有編譯單元中也都相同。
|
在命名空間範圍的 inline const 變數預設具有 外部連結性(不同於非 inline、非 volatile 的 const 限定變數)。 |
(自 C++17 起) |
inline 關鍵字的最初意圖是作為一種指示,告訴優化器:比起函式呼叫,更偏好函式的 inline 替換 (inline substitution);也就是說,不執行轉移控制權至函式本體的 CPU 函式呼叫指令,而是直接執行函式本體的副本,而不產生呼叫。這避免了函式呼叫產生的開銷(傳遞參數及取得結果),但可能會導致執行檔變大,因為函式的程式碼必須重複多次。
由於 inline 替換在標準語義中是不可觀察的,編譯器可以自由地對任何未標記為 inline 的函式進行 inline 替換,也可以自由地對任何標記為 inline 的函式產生函式呼叫。這些優化選擇並不會改變上述關於多重定義和共用靜態變數的規則。
|
因為從 C++98 起,關鍵字 inline 對函式的意義變成了「允許重複定義」而非「偏好 inline 化」,該意義隨後也被擴展到了變數。 |
(自 C++17 起) |
[編輯] 筆記
如果具有外部連結性的 inline 函式或變數(自 C++17 起)在不同編譯單元中的定義不一致,則程式格式錯誤 (ill-formed),且不要求診斷資訊。
inline 指定子不能用於塊範圍(block scope,即在另一個函式內部)的函式或變數(自 C++17 起)宣告。
inline 指定子不能重新宣告在同一個編譯單元中已被定義為非 inline 的函式或變數(自 C++17 起)。
隱含產生的成員函式,以及任何在首次宣告時宣告為 defaulted 的成員函式,都像任何定義在類別定義內部的函式一樣,是 inline 的。
如果在不同編譯單元中宣告了某個 inline 函式,則在每個編譯單元結束時,累積的預設參數 (default arguments) 集合必須相同。
在 C 語言中,inline 函式不一定要在每個編譯單元中都被宣告為 inline(最多可以有一個非 inline 或 extern inline 定義),函式定義不一定要完全相同(但如果程式行為依賴於呼叫哪一個定義,則該行為是未定義的),且同一個函式的不同定義之間的函式區域靜態變數是各自獨立的。
|
關於 inline 靜態成員的額外規則,請參閱靜態資料成員。 Inline 變數消除了將 C++ 程式碼打包為 header-only 函式庫的主要障礙。 |
(自 C++17 起) |
| 特性測試巨集 | 數值 | 標準 | 功能 |
|---|---|---|---|
__cpp_inline_variables |
201606L |
(C++17) | Inline 變數 |
[編輯] 關鍵字
[編輯] 範例
標頭檔 "example.h"
#ifndef EXAMPLE_H #define EXAMPLE_H #include <atomic> // function included in multiple source files must be inline inline int sum(int a, int b) { return a + b; } // variable with external linkage included in multiple source files must be inline inline std::atomic<int> counter(0); #endif
原始碼檔案 #1
#include "example.h" int a() { ++counter; return sum(1, 2); }
原始碼檔案 #2
#include "example.h" int b() { ++counter; return sum(3, 4); }
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 281 | C++98 | friend 函式宣告可以使用 inline 指定子 即使被宣告為 friend 的函式本身並非 inline 函式 |
禁止此類用法 |
| CWG 317 | C++98 | 函式即使在同一個編譯單元中已被定義為非 inline 在其定義之後仍可被宣告為 inline |
在這種情況下,程式格式錯誤 formed in this case |
| CWG 765 | C++98 | 定義在 inline 函式中的型別可能 在不同編譯單元中有所不同 |
此類型別在所有 編譯單元中皆應相同 |
| CWG 1823 | C++98 | inline 函式所有定義中的字串實字 需跨編譯單元共用 |
由於一致性與實作上的考量, 此項要求已被移除 |
| CWG 2531 | C++17 | 靜態資料成員即使未在首次宣告時 宣告為 constexpr,也可能隱含地為 inline |
在此情況下它不應 隱含地為 inline |
[編輯] 參閱
| 關於 inline 的 C 語言文件
|