2017-02-22 59 views
1
class A { 
    public: 
     int a; 
     char b; 
     double c; 
     A (int x, char y, double z) : a(x), b(y), c(z){} 
}; 

int main(){ 

    auto lambda = [](auto x) { 
     static auto y = x; 
     // y = x; 
     return y; 
    }; 

    int a = lambda(1); 
    char b = lambda('a'); 
    double c = lambda(1.5); 
    A  d = lambda(A(2, 'b', 2.5)); 

    return 0; 
} 

此代碼在Clang 3.8.0和GCC 5.4.0中編譯,並且正常工作。然而,該變量y是考慮到staticC++中的泛型Lambda中的靜態自動變量14

  • 什麼是可變y的類型?每次調用lambda時,y的類型是否會改變?
  • 可變y初始化在每次調用盡管是static?註釋分配// y = x不需要更新變量y的值。
  • Is this C++ 14 Standard compliant?

如果我在每次打印中打印sizeof(y),我分別得到4,1,8和16。

On local and global static variables in C++

+2

的通用拉姆達的'操作符(...)'是更多或更少的功能* -模板*。因此,將爲每個單獨的函數實例創建靜態變量。 – WhiZTiM

回答

4

你拉姆達是通用。這意味着這是一個僞裝的模板。情況按照模板專業化的一般規則處理。

對於x你得到你的函數的一個獨立的專業化每一個具體推導類型的參數。所以,對於每種特定類型的x,您都會獲得y的單獨副本。但是底層機制並不是以你的方式定位在你的static,而是你的函數的整個主體被「複製」以產生一個獨立的函數實現。

你的lambda的每個專長都會有一個y的單獨副本,在第一次調用該特定專業化時,它將僅被初始化一次。

的情況是幾乎相當於一個更明確的

template <typename T> void foo(T x) 
{ 
    static T y = x; 
    std::cout << y << std::endl; 
} 

int main() 
{ 
    foo(1); 
    foo('a'); 
    foo(1.5); 
    foo(3.0); 
} 

其輸出1a1.51.5

在本例中,您獲得了三個獨立的專業foofoo<int>foo<char>foo<double>foo的每個版本都獲得其自己的版本y,這意味着在此示例中有三個不同的靜態y。對每個專業化的第一次調用將初始化y,隨後的調用不會重新初始化它。在這種情況下調用foo(1.5)初始化yfoo<double>,但foo(3.0)後續調用不會。

同樣的事情在你的情況同樣會發生,它只是使用了不同的語法。

+0

太棒了!這很有道理。我還打印變量'y'的地址,實際上它與使用不同類型的lambda的調用不同,並且它是具有相同類型參數的調用的相同地址。我知道'靜態'變量和模板,但我沒有完全理解這種行爲。現在我做了,非常感謝! –

2

的Lamda與汽車無非是一類多與運營商()重載是一個模板,並使用自動類型推導(下面的規則模板參數扣)。

在這種情況下,你有儘可能多的靜態y字段作爲此函數對象模板操作的許多實例。

初始化就像做過手寫類,這是第一次的功能被觸發(在這種情況下,lambda)