2013-06-04 66 views
2

在一本教科書中,我讀過的內聯函數不能包含遞歸,轉到等等。爲什麼? 我不認爲如果我這樣做會產生語法錯誤。內聯函數不能包含遞歸,去循環等?

+2

這是哪本書? 'inline'只與一個定義規則有關,它不影響你可以在一個函數中使用的功能。 – BoBTFish

+3

可能重複的[可以遞歸函數內聯?](http://stackoverflow.com/questions/190232/can-a-recursive-function-be-inline) –

+0

是不是你用constexpr混淆它?目前的確在許多方面受到限制,直到C++ 14碰到貨架。 –

回答

2

此代碼是完全合法:

class Test 
{ 
    public: 
    inline void sayHello(int i); 
}; 

void Test::sayHello(int i) 
{ 
    std::cout << "Hello "<< i << std::endl; 
    if (i>0) 
    sayHello(i-1); 
} 

int main(int argc, char** argv) { 
    Test t; 
    t.sayHello(10); 
} 

..和遞歸預期。

(GCC 4.6.3)

在這種情況下,該功能不內聯,因爲內聯僅僅是對編譯器的提示。不是要求。

如上意見建議者,在這裏你會發現一個更完整的答案:Can a recursive function be inline?

2

這聽起來像內聯函數的C++的概念,並擴展函數調用內嵌的優化之間的混淆。

內聯函數是在每個使用它的翻譯單元中定義的函數;不像非內聯函數,它必須在每個定義規則的一個翻譯單元中定義。這些功能可以做什麼沒有特別限制;特別是,他們可以像你說的那樣遞歸地調用自己。

內聯函數和優化之間的聯繫是許多編譯器在編譯調用站點時需要定義纔可用;它通常需要內聯函數才能在多個翻譯單元中進行定義。

這本書可能意味着遞歸調用不能以內聯方式擴展,因爲這意味着生成的代碼必須包含自身的副本;那是不可能的。但是,它仍然沒有理由不包含循環,分支或任何其他正常的流程控制語句。

1

正如Mike所說,語言定義對inline函數沒有這樣的限制。你有時看到的是一個編譯器警告,一個函數不是內聯展開的,因爲它使用了一些編譯器不會內聯的語言結構,比如遞歸,循環等。這就是只有告訴你函數不是在線擴展,所以你沒有得到你可能想要的優化。該代碼是有效的,並且生成的可執行文件將正常工作。

3

您的教科書有誤。

首先,理解「聲明函數爲inline」和實際的「函數調用內聯」的概念之間的區別很重要。前者適用於函數本身,後者適用於每個獨立的調用。

現在,內聯函數可以包含任何東西。幾乎任何直接調用任何函數都可以內聯。沒有任何限制。

內聯代碼中包含循環或本地gotos顯然沒有問題。所以,當你的書說內聯函數「不能包含循環或gotos」時,它必須指向一些特定的(也許很老的)編譯器的怪癖,由於某些實現特定的原因,這些編譯器不能內聯這些函數。

遞歸是一個不同的故事。顯然,如果在編譯時未知道遞歸的深度,則不可能完全嵌套全部嵌套的遞歸調用。然而,仍然有可能將遞歸「展開」到特定的有限深度。即編譯器可以內聯遞歸調用,例如深度5級,然後繼續進行真正的(非內聯)遞歸調用。這與稱爲「循環展開」的優化技術沒有多大區別。所以,即使是遞歸函數也可以內聯。一些編譯器甚至可以讓您控制遞歸函數的內聯擴展深度。

0

我們可以在內聯函數中使用循環,遞歸等。但是對於一個好的編程習慣,我們不這麼做;因爲對於循環寫入的指令,每一次執行都必須由我的CPU進行管理。它可以消耗內存中的一些額外空間。