2009-12-26

関数の宣言の順序

ふと、こんなつぶやきを聞いた気がする。

struct foo { auto f()->int && { ... } }; って、int f() && か、int && f() のどっちに解釈されるの?

誰がつぶやいたのか覚えがないが、同時に、「プリプロセッサたんは俺の嫁」というつぶやきも聞いた気がする。不思議なことだ。一体誰がつぶやいたのだろう。それに、俺の嫁はUnified Function Sytanx(統一関数文法)たんに決まっている。New function declaration syntax(新関数宣言文法)たんでは、断じてない。

それ以降、つぶやきは聞こえなくなってしまった。おそらくは自力で問題を調べ、わざわざ答えをつぶやくまでもない、しごく簡単な疑問だということに気がついたのだろう。結論から言うと、

struct foo
{
    auto f() ->int && ;
} ;

この新しい関数宣言の記法を使ったコードは、従来の関数宣言の文法を使えば、

struct foo
{
    int && f() ;
} ;

このように書くことが出来る。一方、*thisへのref-qualiferを指定したければ、

struct foo
{
    auto f() && -> int  ;
} ;

このようになる。理由は簡単明白だ。規格をちらと見ただけで、見逃しようもないほどはっきりと書いてある。

In a declaration T D where D has the form

D1 ( parameter-declaration-clause ) attribute-specifieropt cv-qualifier-seqopt ref-qualifieropt exception-specificationopt trailing-return-type

and the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T”, T shall be the single type-specifier auto.

つまり、順番がわかりやすいように、全部を使ってメンバ関数を長々と書くと、以下のようになる。

struct foo
{
    auto            // T はautoでなければならない。
    f               // 関数の名前
    (void)          // 引数リスト
    [[]]            // attribute
    const volatile  // cv-qualifier
    &&              // ref-qualifer
    throw()         // exception specification
    -> int &&       // 戻り値の型
    ;               // expression-statementの終端記号
} ;

これを、従来の関数の文法と比べてみると、以下のようになる。

// 従来の文法
int && f(void) [[]] const volatile && throw() ;

// 新文法
auto f(void) [[]] const volatile && throw() -> int && ;

ちなみに、Unified Function Syntaxが可決された暁には、autoが[]になる。

[] f() -> int ;

Unified Function Sytanxは、とても素晴らしいので、是非とも規格入りしてもらいたい。

No comments: