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

altebute.hatenablog.com

犬も歩けば規格にあたる

VC++2013 で using 宣言を使うだけでコンパイラが強制終了するコード

以下のプログラムは VC++2013 で正しく動作する。

template< typename Head, typename... Tail >
struct s;

template< typename Last >
struct s< Last >
{
    void f( Last ) {}
};

template< typename First, typename Second, typename... Tail >
struct s< First, Second, Tail... >
: s< Second, Tail... >
{
    using s< Second, Tail... >::f;
    void f( First ) {}
};

int main() {}

template の再帰を用いた典型的な記法である。 *1

派生クラスで宣言、定義した関数 f によって、基底クラスの関数 f が隠蔽されてしまうため、 using 宣言によって名前をスコープに持ち込む。

ところが、以下のように書き換えるだけで VC++2013 ではコンパイラが動作を停止してしまう。

致命的なエラー C1001

template< typename First, typename Second, typename... Tail >
struct s< First, Second, Tail... >
: s< Second, Tail... >
{
    void f( First ) {}
    using s< Second, Tail... >::f;
};

関数 f と using 宣言の順番を入れ替えただけでコンパイラが動作停止。とても残念。 VC++2015 では動くのかもしれないが未検証。 *2 当然だが gcc と clang では動作した。

また、以下のコードも NG 。

template< typename Arg >
struct impl
{
    void f( Arg ) {}
};

template< typename Head, typename... Tail >
struct s;

template< typename Last >
struct s< Last >
: impl< Last >
{};

template< typename First, typename Second, typename... Tail >
struct s< First, Second, Tail... >
: s< First >
, s< Second, Tail... >
{
    using  s< First >::f;
    using  s< Second, Tail... >::f;
};

int main() {}

これが出来ないので、再帰テンプレートによる構造部分と、関数を宣言する構造部分を分離することが出来ない。

辛い。

*1:テンプレート型引数が2個以上である場合の特殊化を明示しているのは、古い VC++ では明示的に書かないと曖昧と判断されてしまうため

*2:2016.07.22 VC++2015 では正常に動作した。