12

次のコードを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は特定の理由で準拠しています)?

4

1 に答える 1

9

私の解釈は正しいですか[...]?

はい。

あなたが引用した基準の段落のため、あなたの解釈は正しいです。さらなる確認は、参照バインディングに関するパラグラフ13.3.3.1.4/3から得られます。

13.3.1を参照する暗黙のオブジェクトパラメータを除いて、非揮発性const型への参照以外の左辺値参照を右辺値にバインドするか、右辺値参照を左辺値にバインドする必要がある場合、標準の変換シーケンスを形成できません。関数左辺値以外。[...]

13.3.3.2/3項には、さらに(間接的な)確認が含まれています。

[...]標準変換シーケンスS1は、標準変換シーケンスS2よりも優れた変換シーケンスです。

— [...]

— S1とS2は参照バインディング(8.5.3)であり、S1は左辺値参照を関数左辺値にバインドし、S2は右辺値参照を関数左辺値にバインドします。[

int f(void(&)()); // #1
int f(void(&&)()); // #2
void g();
int i1 = f(g); // calls #1

—<em>例を終了]

于 2013-03-23T17:49:11.727 に答える