読者です 読者をやめる 読者になる 読者になる

とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

関数型とはいったい…

関数型とはいったいなんなんでしょう? lvalue なのでしょうか, rvalue なのでしょうか?
次のコードをコンパイルしてみます。

void f(){}
int i;

int main()
{
 {
  void (&f_ref)() = f;
  void (&&f_ref2)() = f;
  void (&&f_ref3)() = f_ref;
 }
 {
  int& i_ref = i;
  // int&& i_ref2 = i;
  // int&& i_ref3 = i_ref;
 }
}

GCC 4.7.0 では通りますが,VC++10では

a.cpp
a.cpp(8) : error C2440: '初期化中' : 'void (__cdecl *)(void)' から 'void (__cdecl &&)(void)' に変換できません。
        スコープ内でこの名前を指定された関数でターゲット型に一致するものはありません。

と言われます。f_ref2 の初期化はどっちの挙動が正しいのでしょうか?
興味深いことにどちらでも f_ref3 の初期化は通ります。(当然ながら)どちらでも i_ref3 の初期化が通らないのとは対照的です。関数は何か特別なのでしょうか?
残念ながらドラフトを調べてみましたが,自力では解決できませんでした。どなたか教えてください。

追記

Twitter で教えてもらいました。




とのことで,「関数は lvalue 。関数は特別に lvalue で rvalue リファレンスを初期化できる」が正しいようです。GCC 4.7.0 の挙動でいいみたい。
ドラフト(N3290)からも引用しておきます。(自分が正しい場所を読んでいるのか自信ないので)

8.5.3 References [dcl.init.ref]
(snip)
5 A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:
(snip)
— Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference. (snip)
— If the initializer expression
— is an xvalue, class prvalue, array prvalue or function lvalue and “cv1 T1” is referencecompatible with “cv2 T2”(snip)
then the reference is bound to the value of the initializer expression in the first case