2012-07-17 44 views
6

的C++ 11標準說(或至少,我有版本 - 不是最後一個):爲什麼隱式的「lambda轉換爲函數指針」禁止「通過引用」捕獲靜態成員?

該閉合類型與沒有λ-捕獲的λ-表達具有 公共非虛擬非顯式常量轉換函數指向 ,其功能與封閉類型的函數調用操作符具有相同的參數和返回類型。

我明白爲什麼從一個有狀態的lambda函數獲取函數指針是不可能的,因爲函數指針本身不能保存任何數據。

但是,當捕獲的對象只是一個靜態成員/靜態變量時,不存在這樣的限制,因爲捕獲的對象的引用可以在函數本身中硬連線。

struct A { 
    static int count = 0; 
    void foo() { 
     static int bar = 0; 
     auto fun = [&]()->void { 
      count++; 
      bar++; 
     }; 
     void(*ptrFun)(); 
     ptrFun = fun; // forbidden by the quoted wording 
    } 
}; 

爲什麼在前者無狀態時,將lambda函數轉換爲函數指針是不可能的?我是否錯過了一些東西,或者委員會是否忘記了這一點?

+1

我猜測這是爲了避免要求編譯器能夠證明什麼被捕獲。 – Flexo 2012-07-17 22:59:25

+0

編譯器只要使用它們就已經能夠自動捕獲變量(使用自動[&]),所以它不會涉及更多的工作來檢查它們是靜態成員還是全局變量,因爲它們必須之前已宣佈。 – 2012-07-17 23:05:17

+0

其實我沒有在任何編譯器上測試過它(我只有MSVC10,它根本不支持函數指針轉換)。我想這是一個GCC擴展?無論如何,我的問題是:標準允許(也許我錯過了什麼)?如果不是,爲什麼它被禁止(也許有一個我不知道的技術限制)? – 2012-07-17 23:11:09

回答

9

A::count根本不需要被捕獲。只需要捕獲this和局部變量。無需捕獲具有靜態存儲持續時間的變量(例如,靜態數據成員,名稱空間範圍變量或本地函數靜態變量),因爲它們是「唯一」的。每個這樣的變量只有一個實例,因此不需要捕獲對象的引用。

如果您從您的lambda中刪除默認捕獲(即,將[&]更改爲[])並定義count,則應該編譯時不會出錯。 (我已經驗證了Visual C++ 2012 RC和g ++ 4.5.1都接受代碼;我必須做的唯一更改是移動count的內聯初始化,因爲這些編譯器都不支持該C++ 11功能。 )

+0

當然是的......我現在感覺很蠢:)但是,如果我們想要捕獲一個靜態局部變量呢? – 2012-07-17 23:40:53

+0

由於相同的原因,它們也不需要被捕獲:每個靜態局部變量都是「唯一」的並且具有已知地址。我已經修改了答案以引用「具有靜態存儲持續時間的變量」。這裏仍然有一些細微之處,儘管我沒有意識到(VC11和g ++ 4.5.1都接受'count'作爲命名空間範圍變量,靜態數據成員或作爲函數的程序)本地靜態)。 – 2012-07-17 23:47:20

+0

我不知道它被允許,謝謝! – 2012-07-18 08:13:39

相關問題