次のコードをGCC、Clang、ICC、およびVSでテストしました。
void f() {}
void g(void (&&)()) { }
int main() {
g(f);
}
ご覧のとおりg
、右辺値参照を取りますがf
、左辺値であり、一般に、右辺値参照を左辺値にバインドすることはできません。それはまさにICCが不平を言っていることです:
error: an rvalue reference cannot be bound to an lvalue
VSもエラーを出しますが、別の理由があります。
error C2664: 'void h(void (__cdecl &&)(void))' : cannot convert parameter 1 from 'void (__cdecl *)(void)' to 'void (__cdecl &&)(void)'
これは、VSが参照をに直接バインドするのではなく、関数からポインタへの変換をすぐに実行していることを私に示唆していますf
。に置き換えるg(f)
とg(&f)
、4つのコンパイラでこれとまったく同じエラーが発生することに注意してください。
最後に、GCCとClangはコードを受け入れ、正しいと思います。私の推論は8.5.3/5に基づいています
タイプ「cv1T1」への参照は、タイプ「cv2T2」の式によって初期化されます。
—参照が左辺値参照の場合[...]
—それ以外の場合、[...]参照は右辺値参照になります。
—初期化式が[...]関数左辺値[...]の場合
次に、参照は初期化式の値にバインドされます[...]
私の解釈は正しいですか(つまり、ClangとGCCは特定の理由で準拠しています)?