[英]Rvalue reference and auto&& local variables
將局部變量定義為右值引用或轉發(通用)引用有什么意義? 據我所知,任何具有名稱的變量都是左值,並將被視為向前移動。
例:
Widget&& w1 = getWidget();
auto&& w2 = getWidget();
w1和w2都是左值,如果它們稍后作為參數傳遞,將被視為左值。 他們的decltype可能不是,但這有什么區別? 為什么有人需要這樣定義變量?
如果你有一個函數返回一個無法移動的臨時函數。
Foo some_function();
auto&& f = some_function();
這是合法的。 auto f = some_function();
將復制(這可能是昂貴的),或無法編譯(如果該類也無法復制)。
通常, auto&&
可以根據初始化的內容推斷為r或左值引用,如果使用臨時值初始化則延長其生命周期,同時允許您將其作為左值訪問。
經典用法是'just-loop'模式:
for( auto&& x : some_range )
實際上有一個auto&& x = *it;
在生成的代碼中。
您不能將非常量左值引用綁定到臨時值,因此您的另一個選擇是Widget const&
,它不允許您在其生命周期內修改臨時值。
此技術對於分解復雜表達式並查看正在發生的情況也很有用。 只要您不使用極其脆弱的表達式模板,就可以將表達式設為a+b+c*d
並將其轉換為
auto&& c_times_d = d*d;
auto&& b_plus_c_times_d = b + decltype(c_times_d)c_times_d;
auto&& c_plus_b_plus_c_times_d = c + decltype(b_plus_c_times_d)b_plus_c_times_d;
現在您可以訪問其生命周期延長的臨時對象,並且您可以輕松地逐步執行代碼,或者在復雜表達式中的步驟之間引入額外的步驟:這是機械地發生的。
如果您未能綁定每個子表達式,則只關注脆弱的表達式模板。 (請注意,使用->
可以生成大量您可能不會注意到的子表達式。)
當我想說“我正在存儲某些函數的返回值,而不是復制”時,我使用auto&&
,並且表達式的類型並不重要。 auto
是我想制作本地副本的時候。
在通用代碼中,它非常有用。
Foo const& a(Foo*);
Bar a(Bar*);
template<class T>
auto do_stuff( T*ptr ) {
auto&& x = a(ptr);
}
這里如果你傳遞一個Bar*
它存儲臨時值,但是如果你將一個Foo*
傳遞給do_stuff
它會存儲const&
。
它盡力而為。
下面是一個返回不可移動的不可復制對象的函數示例,以及auto&&
如何存儲它。 它沒用,但它顯示了它的工作原理:
struct Foo {
Foo(&&)=delete;
Foo(int x) { std::cout << "Foo " << x << " constructed\n";
};
Foo test() {
return {3};
}
int main() {
auto&& f = test();
}
據我所知,沒有真正的,也就是廣泛使用的目的來定義局部右值引用,因為它們的性質,不綁定到左值,只對重載和推導有幫助,所以將它們定義為函數的參數。
可以使用它們,將它們綁定到臨時值,如int &&rref = 5*2;
但由於幾乎所有的編譯器都在優化表達式int i = 5*2;
沒有實際需要,性能不佳或避免復制。
一個例子可以是一個數組
template<class T, int N> using raw_array = T[N];
然后
auto && nums = raw_array<int,4>{101, 102, 103, 104};
這允許臨時使用,就好像它是一個普通的數組。
聲明為auto&&
的變量將遵循完美的轉發規則。 親自試試吧。 這甚至是在c ++ 14中使用lambdas完成轉發的完美方式。
const Type& fun1();
Type&& fun2();
auto&& t1 = fun1(); // works
auto&& t2 = fun2(); // works too
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.