2011-01-07

MSVCのバグだと思ったら、実はGCCの未実装だった

以下のコードはwell-formedなC++0xのコードである。ただし、C++03ではill-formedである。

class Y ;

class X
{
    friend Y ;
} ;

MSVCでコンパイルが通り、GCCでコンパイルが通らなかったので、てっきりまた、MSVCのバグかと思ったが、規格を参照したところ、MSVCの実装はC++0xとして正しいものであった。あやうくMSVCにバグ報告するところであった。危ない危ない。もちろん、ただしくGCCの方にバグ報告しておいた。

追記:バグではなく、未実装なのだという。まさかこのページのExtended friend declarationsがこれを意味するとは思わなかった。また、MSVCも、C++0xを実装しているというより、独自仕様である。C++0xの規定するfriend宣言をすべて実装しているわけではない。

C++0xでは、type specifierがクラスの型を表す場合、friendクラスの宣言として扱われる。C++03では、friendクラスの宣言は、常にelaborated-type-specifierを使わなければならなかった。つまり、class-keyが必須だったのである。

// C++03対応版
class X
{
    friend class Y ;
} ;

もちろん、あらかじめ名前が宣言されていない場合は、C++0xでもエラーになる。

class X
{
    friend Y ; // エラー、Yは宣言されていない
    friend class Y ; // OK
} ;

ちなみに、type specifierがclass typeではない場合、無視される。これはどういう事かというと、例えば以下のようなコードが通るということだ。

template < typename T >
class X
{
    friend T ; // C++03ではエラー
} ;

X<int> x ; // friend宣言は無視される

この場合、friend宣言は、friend int ; という、意味のないものになってしまう。幸いにして、C++0xでは、単に無視される。その結果、コンパイルが通る。これにより、テンプレートコードが書きやすくなる。

コメントにも書いたように、C++0xでは、friendにtemplate parameterを使えるようになったが、それは、このブログの読者ならば、すでにご存知だろう。

No comments: