[英]Why cast expression to rvalue reference to function is lvalue?
在這里, cppreference-lvalue ,我發現了
將表達式轉換為對函數的rvalue引用是lvalue。
我很好奇,所以我進行了以下實驗:
#include <iostream>
using namespace std;
typedef void (&&funr) (int);
typedef void (&funl) (int);
void test(int num){
cout<<num<<endl;//output:20
}
void foo(funr fun){
fun(10);
}
void foo(funl fun){
fun(20);//call this
}
template <typename T> void foo(T&& fun){
cout<<is_same<T,void(&)(int)>::value<<endl;//true, it is lvalue.
cout<<is_same<T,void(int)>::value<<endl;//false, it isn't rvalue.
}
int main()
{
foo(static_cast<void(&&)(int)>(test));
return 0;
}
這樣的事實。
為什么將表達式轉換為rvalue對函數的引用是lvalue? 是因為函數類型不需要移動語義或其他東西嗎? 或者我理解這個詞錯了。
將表達式轉換為對函數的rvalue引用是lvalue
它遵循C ++ 11 3.10 / 1中的值類別的定義(強調我的):
左值 (...)表示函數或對象。 ...
xvalue (“eXpiring”值)也指對象,......
rvalue (...)是xvalue,臨時對象(12.2)或其子對象,或者與對象無關的值。
prvalue (“純”rvalue)是一個不是xvalue的rvalue。 ...
請注意,只有左值類別可以是一個函數,所有其他類別只是值或對象。
它也在5.2.9 / 1中得到回應:
表達式
static_cast<T>(v)
的結果是將表達式v
轉換為類型T
。 如果T
是左值引用類型或函數類型的右值引用,則結果為左值 ; 如果T
是對象類型的右值引用,則結果為xvalue; 否則,結果是prvalue。 ...
至於它的原因,我當然只能猜測(不是標准化委員會的一部分)。 但我的猜測是,擁有函數類型的rvalues是沒有意義的 - 函數永遠不會是臨時函數,它永遠不會處於或接近其生命周期的末尾。
非常感謝TC提供的信息( N3055 ,他的評論鏈接),以便快速概述答案,並引用與此問題相關的一些段落。 這個答案告訴我們原因
rvalue引用(如傳統的左值引用)可以綁定到函數。 然而,將rvalue參考返回值作為rvalue處理,將函數rvalue的新概念引入到語言中。 之前沒有這樣的想法 - 在右值上下文中使用的函數左值變為指向函數的rvalue,而不是函數rvalue - 因此當前的標准草案沒有描述如何處理這樣的右值。 特別是,函數調用和函數指針的轉換是根據函數左 值來 指定的, 因此對函數的右值引用的最合理使用在當前的措辭中是未定義的。
這些問題的一種可能的解決方案是保持當前的方法將右值參考返回值視為右值,但是為rvalues的規范添加各種警告,以便來自右值參考的那些具有特殊特征。 這可以稱為“有趣的左值”方法。 然而,進一步檢查標准草案的當前措辭表明,上面列出的問題可能只是冰山一角:許多規范應適用於右值引用所引用的對象,例如對象生存期,別名規則等等,用左值表示, 因此右值警告列表可能會很長 。
這表明了一種替代方法:rvalue引用返回值實際上應該被視為左值,除了一些例外,允許在預期的情況下將它們視為rvalues,即在引用綁定,重載決策和模板參數中扣除。 這個被稱為“有趣的左值”方法的想法體現在本文的早期版本中。經過匹茲堡核心工作組(2010年3月8日至13日)的廣泛討論 ,......
另外,As 5.2.2函數調用[expr.call]說:
對於非成員函數或靜態成員函數的調用,后綴表達式應該是引用函數的左值 (在這種情況下,后綴表達式上的函數到指針標准轉換(4.3)被抑制),或者它應具有指向函數類型的指針。
現在static_cast<void(&&)(int)>(test)
是一個左值。
所以static_cast<void(&&)(int)>(test)(555);
沒關系
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.