6 5 特殊用途語言特性

2022-09-22 03:51:11 字數 3184 閱讀 4302

目錄6.5.2 內聯函式和constexpr函式

constexpr函式

某些函式有這樣一種形參,在函式的很多次呼叫中它們都被賦予乙個相同的值,此時,我們把這個反覆出現的值稱為函式的預設實參(default argument)。呼叫含有預設實參的函式時,可以包含該實參,也可以省略該實參。

例如,我們使用string物件表示視窗的內容。一般情況下,我們希望該視窗的高、寬和背景字元都使用預設值。但是同時我們也應該允許使用者為這幾個引數自由指定與預設值不同的數值。為了使得視窗函式既能接納預設值,也能接受使用者指定的值,我們把它定義成如下的形式:

typedef string::size_type sz;

string screen(sz ht = 24; sz wid = 80; char backgrnd = ' ');

注意:一旦某個形參被賦予了預設值,它後面的所有形參都必須有預設值

string window;

window = screen(); //screen(24,80,' ')

window = screen(66); //screen(66,80,' ')

window = screen(66,256); //screen(66,256,' ')

window = screen(66,256,'#'); //screen(66,256,'#')

函式呼叫時實參按其位置解析,預設實參負責填補函式呼叫缺少的尾部實參(靠右側位置)。例如,要想覆蓋backgrnd 的預設值,必須為ht和 wid提供實參:

window = screen(, ,'?'); //錯誤:只能省略尾部實參

window = screen('?'); //呼叫screen('?', 80, '?')

需要注意,第二個呼叫傳遞乙個字元值,是合法的呼叫。然而儘管如此,它的實際效果卻與書寫的意圖不符。該呼叫之所以合法是因為'?'是個 char,而函式最左側形參的型別string::size_type是一種無符號整數型別,所以char型別可以轉換成(參見4.11節,第141頁)函式最左側形參的型別。當該呼叫發生時,char型別的實參隱式地轉換成string::size_type,然後作為 height的值傳遞給函式。在我們的機器上,'?'對應的十六進製制數是0x3f,也就是十進位制數的63,所以該呼叫把值63傳給了形參height。

當設計含有預設實參的函式時,其中一項任務是合理設定形參的順序。盡量讓不怎麼使用預設值的形參出現在前面,而讓那些經常使用預設值的形參出現在後面。

對於函式的宣告來說,通常的習慣是將其放在標頭檔案中,並且乙個函式只宣告一次,但是多次宣告同乙個函式也是合法的。不過有一點需要注意,在給定的作用域中乙個形參只能被賦予一次預設實參。換句話說,函式的後續宣告只能為之前那些沒有預設值的形參新增預設實參,而且該形參右側的所有形參必須都有預設值。假如給定

//表示高度和寬度的實參沒有預設值

string screen(sz , sz , char = ' ');

//我們不能修改乙個已經存在的預設值

string screen(sz , sz , char = '*'); //錯誤:重複宣告

//但是可以按照如下方式新增預設實參

string screen(sz = 24, sz = 80, char ); //正確:新增預設實參

通常,應該在函式宣告中指定預設實參,並將該宣告放在合適的標頭檔案中。

區域性變數不能作為預設實參。除此之外,只要表示式的型別能轉換成形參所需的型別,該表示式就能作為預設實參:

//wd、def和ht的宣告必須出現在函式外

sz wd = 80;

char def = ' ';

sz ht();

string screen(sz = ht(), sz = wd, char = def);

string window = screen(); //呼叫screen(ht(), 80, ' ')

用作預設實參的名字在函式宣告所在的作用域內解析,而這些名字的求值過程發生在函式呼叫時:

void f2()
我們在函式f2內部改變了def的值,所以對screen的呼叫將會傳遞這個更新過的值。另一方面,雖然我們的函式還宣告了乙個區域性變數用於隱藏外層的 wd,但是該區域性變數與傳遞給screen的預設實參沒有任何關係。

在6.3.2節(第201頁)中我們編寫了乙個小函式,它的功能是比較兩個string形參的長度並返回長度較小的 string 的引用。把這種規模較小的操作定義成函式有很多好處,主要包括:

然而,使用shorterstring函式也存在乙個潛在的缺點:呼叫函式一般比求等價表示式的值要慢一些。在大多數機器上,一次函式呼叫其實包含著一系列工作:呼叫前要先儲存暫存器,並在返回時恢復;可能需要拷貝實參;程式轉向乙個新的位置繼續執行。

將函式指定為內聯函式(inline),通常就是將它在每個呼叫點上「內聯地」展開。假設我們把shorterstring函式定義成內聯函式,則如下呼叫

cout《在編譯時,內聯函式的內容會直接拷貝到呼叫位置上,上述內聯函式在編譯時展開為:

cout<< (s1.size() < s2.size() ? s1 : s2) 《這樣,既保證了可讀性與復用性,又消除了直接呼叫函式shortstring()函式的開銷

在shorterstring 函式的返回型別前面加上關鍵字inline,這樣就可以將它宣告成內聯函式了:

//內聯版本:尋找兩個string物件中較短的那個

inline const string &

shortstring(const string &s1, const string &s2)

一般來說,內聯機制用於優化規模較小、流程直接、頻繁呼叫的函式。同時,很多編譯器都不支援內聯遞迴函式,而且乙個75行的函式也不大可能在呼叫點內聯地展開。

c++11 constexpr:驗證是否為常量表示式

C 特殊用途語言特性

一,預設實參 有一種形參,在函式的很多次呼叫中他們都被賦予乙個相同的值,此時把這個反覆出現的值稱為函式的預設實參 呼叫含有預設實參的函式時,可以包含該實參,也可省略。但是省略必須是省略後面的,所以讓不怎麼使用預設值的形參出現在前面,經常使用預設值的出現在後面 typedef string size ...

union的特殊用途

以下注釋記錄了近期的工作內容,其中主角是c c 的關鍵字union的特殊用法 專案1.版本1 struct a 新專案組成立 專案2 svn建立分支,複製 專案1.版本2 專案2.版本1 struct a struct a 功能1 void func int age void func dword ...

finally的特殊用途

finally允許你定義乙個finally block 若try block被執行則這個finally block必定被執行,即使try block中發生了跳轉或者異常 它會在跳轉或異常前執行 function test finally test 這個特性很重要,它允許我們做某些事情 比如觸發事件的...