2012-10-28 45 views
3

我試探性的答案是否定的,通過下面的測試代碼觀察:C++ 11是否優化了lambdas中的尾遞歸調用?

#include <functional> 
#include <iostream> 
#include <string> 
#include <vector> 

using namespace std; 

void TestFunc (void); 
int TestFuncHelper (vector<int>&, int, int); 

int main (int argc, char* argv[]) { 
    TestFunc(); 
    return 0; 
} // End main() 

void TestFunc (void) { 
    // Recursive lambda 
    function<int (vector<int>&, int, int)> r = [&] (vector<int>& v_, int d_, int a_) { 
     if (d_ == v_.size()) return a_; 
     else return r (v_, d_ + 1, a_ + v_.at (d_)); 
    }; 
    int UpperLimit = 100000; // Change this value to possibly observe different behaviour 
    vector<int> v; 
    for (auto i = 1; i <= UpperLimit; i++) v.push_back (i); 
    // cout << TestFuncHelper (v, 0, 0) << endl; // Uncomment this, and the programme works 
    // cout << r (v, 0, 0) << endl; // Uncomment this, and we have this web site 
} // End Test() 

int TestFuncHelper (vector<int>& v_, int d_, int a_) { 
    if (d_ == v_.size()) return a_; 
     else return TestFuncHelper (v_, d_ + 1, a_ + v_.at (d_)); 
} // End TestHelper() 

有沒有辦法強制編譯器優化的lambda表達式的遞歸尾調用?

在此先感謝您的幫助。

編輯

我只是想澄清,我的意思是問,如果C++ 11優化了lambda表達式的遞歸尾調用。我使用的是Visual Studio 2012,但如果絕對知道GCC執行所需的優化,則可以切換環境。

+0

你正在使用什麼編譯器; http://stackoverflow.com/questions/5231823/vs2010-c-tail-call-optimization?rq=1似乎表明,vs2010可以做一些尾巴呼叫,或者你是否特別提到lambdas – Foon

+2

該語言,儘可能我知道,對此沒有提及。如果你問一個特定的編譯器是否執行這種優化,你應該告訴我們你正在使用什麼編譯器(並且可能會重新解釋這個問題)。 –

+0

我正在使用Visual Studio 2012.是的,正如問題所示,看起來實際功能正在優化,但不是lambda。我想知道是否有一個編譯器開關可以用來強制編譯器優化lambda表達式。 – Shredderroy

回答

7

你實際上並沒有在「lambda」代碼中進行尾部調用,至少不是直接進行。 std::function是一個多態函數包裝器,這意味着它可以存儲任何種類的可調用實體。 C++中的lambda具有唯一的未命名類類型,不是一個對象,它們可以存儲在其中。

由於std::function使用類型擦除,它必須跳過幾個箍來調用最初傳遞給它的東西。這些循環通常使用虛擬函數或功能指針來完成功能模板特化,並且可以使用void*

間接性的唯一性使其很難讓優化者看穿它們。同樣,編譯器很難看到std::function並決定是否有尾遞歸調用。

另一個問題是r可能會從r或同時更改,因爲它是一個簡單的變量,並且突然間您不再有遞歸調用!使用函數標識符,這是不可能的,但它們不能在中途改變含義。

我只是想澄清一下,我的意思是問C++ 11是否優化了lambda表達式中的遞歸尾調用。

C++ 11標準描述了抽象機器上的工作程序是如何工作的,而不是編譯器如何優化工具。實際上,如果編譯器不改變程序的可觀察行爲(使用copy-elision /(N)RVO作爲例外),則只允許編譯器進行優化。

+2

它應該遵循,如果你想做遞歸調用,lambda表達式可能不是最好的工具。 –

+0

要記住一個重要的警告。我不記得在'C#'中遇到'Func <>'這樣的問題,所以我可能沒有在C++中尋找這個問題。我應該檢查我的代碼。 – Shredderroy