簡體   English   中英

如果返回一個向量項,那么lambda表達式的返回類型是什么?

[英]What is the return type of a lambda expression if an item of a vector is returned?

請考慮以下代碼段:

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

int main() 
{
    std::vector<int>v = {0,1,2,3,4,5,6};
    std::function<const int&(int)> f = [&v](int i) { return v[i];}; 
    std::function<const int&(int)> g = [&v](int i) -> const int& { return v[i];};

    std::cout << f(3) << ' ' << g(3) << std::endl;
    return 0;
}

我期待相同的結果:在fv由const引用傳遞,因此v[i]應該具有const int& type。

但是,我得到了結果

 0 3

如果我不使用std :: function,一切都很好:

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

int main() 
{
    std::vector<int>v = {0,1,2,3,4,5,6};
    auto f = [&v](int i) { return v[i];}; 
    auto g = [&v](int i) -> const int& { return v[i];};

    std::cout << f(3) << ' ' << g(3) << std::endl;
    return 0;
}

輸出:

3 3

因此,我想知道:

  1. 在第二個片段中,lambda表達式f的返回類型是什么? f一樣g

  2. 在第一個片段中,構造std::function f時發生了什么,導致錯誤?

lambda的返回類型使用auto返回類型推導規則,它剝離了引用性。 (最初它使用了一組略有不同的規則,這些規則基於左值到右值的轉換(也刪除了引用),但是由DR改變 。)

因此, [&v](int i) { return v[i];}; 返回int 因此,在std::function<const int&(int)> f = [&v](int i) { return v[i];}; ,調用f()返回一個懸空引用。 綁定對臨時的引用會延長臨時的生命周期,但在這種情況下綁定發生在std::function的機器內部,所以在f()返回時,臨時就已經消失了。

g(3)很好,因為const int & return直接綁定到向量元素v[i] ,因此引用永遠不會懸空。

如果返回一個向量項,那么lambda表達式的返回類型是什么?

這是錯誤的問題。

如果沒有明確指定 lambda表達式,你應該問什么是返回類型

答案在C ++ 11 5.1.2 [expr.prim.lambda]第5段中給出,其中它表示lambda是否沒有return expr; 聲明它返回void ,否則:

lvalue-to-rvalue轉換(4.1),數組到指針轉換(4.2)和函數到指針轉換(4.3)之后返回表達式的類型;

(參見下面的TC對DR 1048的評論,它略微改變了這個規則,編譯器實際上實現了更改的規則,但在這種情況下並不重要。)

lvalue-to-rvalue轉換意味着如果return語句返回像v[i]這樣的左值,它會衰減為rvalue,即它只返回int值。

所以你的代碼的問題是lambda返回一個臨時的,但是包裝它的std::function<const int&(int)>綁定了對該臨時的引用。 當您嘗試打印出臨時值已經消失的值(它已經綁定到一個不再存在的堆棧幀的對象),因此您有未定義的行為。

修復是使用std::function<int(int)>或確保lambda返回有效的引用,而不是rvalue。

在C ++ 14中,非lambdas也可以使用返回類型推導,例如:

auto f(std::vector<int>& v, int i) { return v[i]; }

這遵循與lambda的C ++ 11規則類似(但不完全相同)的規則,因此返回類型為int 要返回引用,您需要使用:

decltype(auto) f(std::vector<int>& v, int i) { return v[i]; }
  1. 我假設第一個lambda可能返回intint& ¹。 不是const int&因為引用v不是const對象(捕獲本身不可變是無關緊要的,因為那是引用本身)

  2. 當綁定到const-ref時,臨時值的生命周期延伸到封閉范圍的末尾


¹我稍后會嘗試深入研究。 現在,我會定期演繹直覺並說auto會導致int ,而auto&會推斷int& ,所以我希望實際的返回類型是int 如果有人打敗我,那就更好了。 我幾個小時都沒有時間

請參閱@milleniumbug提供的測試: Live On Coliru

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM