Home > C++ > C++でメンバ関数テンプレートを仮想関数にできないのは何故?

C++でメンバ関数テンプレートを仮想関数にできないのは何故?

  • Posted by: zakio
  • 2009年3月19日 21:44
  • C++

C++ でメンバ関数テンプレートを仮想関数にしようとして、コンパイラに怒られた経験がある人は多いと思う。


class Hoge {
public:
  template <typename T>
  virtual void Func(const T& in) {} // メンバ関数テンプレートは仮想関数にできない
};

こういう場合、クラスを丸ごとテンプレート化してしまえば何とかなる場合が多いので、どうしてもという時は設計を見直すことになるだろう。こうすれば仮想関数でテンプレート引数の型が使えるようになる。


template <typename T> // テンプレートクラスにすれば、仮想関数で T が使える
class Hoge {
public:
  virtual void Func(const T& in) {}
};

仮想関数ではないメンバ関数テンプレートや、テンプレートではない仮想関数は可能なのに、この2つが合わさるとダメになってしまうのは何故なのだろう。短い答えは「そういう仕様だから」だ。C++ の標準規格書には、はっきり「ダメ」と書いてある。

A member function template shall not be virtual. [Example:
    template <class T> struct AA {
        template <class C> virtual void g(C); // error
        virtual void f(); // OK
    };
--end example]


ISO/IEC 14882:2003, 14.5.2 Member templates - 3

でも、これで終わってしまったら面白くないので、もう少し掘り下げてみよう。何故こういう仕様になったのだろうか。テンプレートクラスが仮想メンバ関数を持てるならば、仮想テンプレートメンバ関数を許してくれても良いではないか。

色々調べてみた結果、満足のいく答えは Stroustrup 氏の著書「プログラム言語 C++ 第3版」で見つけることができた。灯台下暗しとはこのことだ。

メンバテンプレートは、virtual 宣言できない。たとえば次の通り。


class Shape {
    // ...
    template<class T> virtual bool intersect(const T&) const = 0; // エラー: virtual テンプレート
};


この例は、文法から逸脱しているものとして扱わなければならない。これを認めると、仮想関数を実装するために伝統的に使われてきた仮想関数テーブルテクニック(§2.5.5)が使えなくなる。誰かが新しい引数型を指定して intersect() を呼び出すたびに、リンカは Shape クラスの仮想テーブルに新しいエントリを追加しなければならなくなってしまう。


プログラム言語 C++ 第3版, 13.6.2 メンバテンプレート

なるほど、納得。全ての翻訳単位をコンパイルしてみないと、仮想関数テーブルが一意に定まらないというわけか。

ところで、何故「仕様だから」で済むような話にここまでこだわるのか。それは C# では仮想メンバ関数にジェネリクス(template のようなもの)が使えると聞いたからだ。C++ 以外の言語はサッパリなので、これを機に少し調べてみようと思ったのだが、その前に出来ない理由を明確にしておこうと思った次第。

C# はこの問題をどうやって解決しているのだろう......と、考えているうちに、なんとなく答えが分かったような気がする。C#(に限らず .NET 系全般)なら Just In Time でコンパイルしてしまえば良いではないか。無いものは作ればいい。リンカが困ったらコンパイル。たぶん、これだな。

Comments:1

zakio Author Profile Page 2009年6月 1日 13:39

続き↓
http://zakio.net/blog/2009/06/01-133549.html

コメントを表示する前に、このブログのオーナーによる承認が必要になることがあります。コメントが表示されない場合は、承認されるまでしばらくお待ちください。

Comment Form

Home > C++ > C++でメンバ関数テンプレートを仮想関数にできないのは何故?

Search
Feeds

Return to page top