2017-03-02 144 views
4
// By const l-value reference 
auto func2 = std::bind([](const std::unique_ptr< std::vector<int> >& pw) // fine 
{ 
    std::cout << "size of vector2: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 

//By non-const l-value reference 
auto func3 = std::bind([](std::unique_ptr< std::vector<int> >& pw) // fine 
{ 
    std::cout << "size of vector3: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 

// By Value 
auto func4 = std::bind([](std::unique_ptr< std::vector<int> > pw) // error 
{ 
    std::cout << "size of vector4: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 
func4(); // without this line, compilation is fine. The VS generates error for the calling of the bind object. 
// By r-value reference 
auto func5 = std::bind([](std::unique_ptr< std::vector<int> >&& pw) // error 
{ 
    std::cout << "size of vector5: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 
func5(); // without this line, compilation is fine. 

爲什麼func4和func5無法編譯?在std :: unique_ptr中使用std :: bind in lambda

+0

你的代碼在VS2015中編譯得很好。請在你身邊顯示錯誤信息。 –

+0

@Martin Zhai,如果添加func4()或func5()這一行,那麼你會看到很多錯誤。 – q0987

+1

你的主要問題是使用'std :: bind'。在發生第一次錯誤之後,你也會(可以預料地)發現其他錯誤。 – Yakk

回答

4

func4產生一個錯誤,因爲lambda的參數是按值傳遞的。但是std::unique_ptr不可複製。

func5是更復雜的,我們可以從文檔std::bind讀:

給定來自先前調用結合,當在一個函數調用表達式g(u1, u2, ... uM)被調用時,所存儲的的調用獲得的對象克對象發生,好像通過std::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)),其中fd是類型std::decay_t<F>的值,綁定參數v1v2,...,vN的值和類型按照以下規定來確定。
...
普通存儲參數arg被傳遞給可調用對象作爲左值參數:在STD中的參數vn ::調用呼叫上面簡單Arg和相應的類型VnT cv &,其中CVg具有相同的簡歷資格。

因此,即使std::make_unique<std::vector<int>>(22, 1)是r值,也會給λ值賦予l值,這與預期的r值不兼容。
這也可以解釋爲什麼func3工作正常。

2

bind返回一個可以被調用多次的函數對象。

它接受它的參數並將它存儲在一個元組(或等價物)中。然後它與其餘的調用第一個參數。這與C++ 17中的std::invoke類似。

對於您的兩個失敗案例,您都不能多次調用lambda。因此,當您調用一次時出現錯誤,因爲綁定假定您想要再次調用它。做其他事情將是瘋狂的,因爲它不知道你從來沒有再次呼籲它在operator()的背景下。

邏輯上,那些呼叫應該失敗。該標準還要求它們失敗,因爲這種情況下的標準在邏輯上表現得很好。


auto funcA = 
    [pw=std::make_unique<std::vector<int>>(22,1)] 
    { 
    std::cout << "size of vector2: " << pw->size() << std::endl; 
    }; 

auto funcB = 
    [pw=std::make_unique<std::vector<int>>(22,1)]() mutable 
    { 
    std::cout << "size of vector2: " << pw->size() << std::endl; 
    }; 

這裏有兩個不同的lambda表達式是做你的代碼做了大致的內容。我們只是捕獲,而不是綁定和通過。

funcA我們有一個const unique_ptr,在funcB我們有一個非constunique_ptr。第二,我們可以搬出獨特的ptr;在第一個,我們不能。

std::bind是在C++中存在的lambda之前編寫的,並且它比使用lambda更不是一個好主意。lambdas中的缺陷大部分已被C++ 14刪除,並且極少數情況下使用bind而不是lambda是一個好主意。

std::bind會產生神祕的錯誤消息,並在一些角落案例中具有神祕的行爲,如將bind的結果傳遞給另一個bind