2

C++ 標準は、クラス テンプレートの仮想メソッドのコードが生成される正確な時点について何か述べていますか?

次の例を検討してください。

class Interface
{
  public:
    virtual void f() = 0;
};

template <unsigned int V>
class A : public Interface
{
  public:
    virtual void f()
    {
    }
};

Interface* instantiate()
{
  // class template instantiation with argument V=0
  return new A<0>();
}

// specialization of f() for template argument V=0
template <> void A<0>::f()
{
  cout << "Output from A<0>::f()" << endl;
};

int main() 
{
  Interface* i = instantiate();
  i->f();
  return 0;
}

クラス テンプレート A は、仮想メソッド f() を宣言します。この例では、関数 instantiate() は、A<0>::f() の明示的な特殊化が行われる前に、クラス テンプレート A を暗黙的にインスタンス化します。上記の例では、クラス テンプレート A の暗黙的なインスタンス化が行われた後に特殊化が行われます。これで、少なくとも私の ARM コンパイラと g++ は A<0>::f() の特殊化されたバージョンを選択します。つまり、main() プログラムは「A<0>::f() からの出力」を画面に表示します。

このクラス テンプレートが暗黙的にインスタンス化された後、クラス テンプレートの仮想メソッドの特殊化を定義するだけで十分であると常に確信できますか? 観察された動作が C++ 標準によって裏付けられていれば、気分が良くなるでしょう。このトピックに関する明確な声明は見つかりませんでした。最も近い部分は 14.7.3/6 で、仮想メソッドに関してはやや不明確です。

テンプレート、メンバーテンプレート、またはクラステンプレートのメンバーが明示的に特殊化されている場合、その特殊化は、暗黙的なインスタンス化を引き起こす特殊化を最初に使用する前に宣言する必要があります。使用が発生します。診断は必要ありません。プログラムが明示的な特殊化の定義を提供しておらず、特殊化が暗黙的なインスタンス化を発生させるような方法で使用されているか、メンバーが仮想メンバー関数である場合、プログラムは不正な形式であり、診断は必要ありません。宣言されているが定義されていない明示的な特殊化に対して、暗黙的なインスタンス化が生成されることはありません

4

2 に答える 2

2

UBだと確信しています。

実際には:

new A<0>()

コンストラクターへの呼び出しを生成し、コンパイラーはその定義を使用できるようにする必要があります。この呼び出しの後に特化しようとするとA<0>::A()、gcc でエラーが発生します。

error: specialization of ‘A<V>::A() [with V = 0]’ after instantiation

コンストラクターには、クラスのポリモーフィック ヘッダーを設定するコードが含まれます。このヘッダーには、vtable へのポインターが含まれます。その vtable は のエントリになりますがInterface::f、この時点では、最終的にそのスロットを埋めるシンボルを宣言していません。明示的な特殊A<0>::f化-したがって、実装の品質の問題になります-はコンパイラを実行しますvtable を設計すると同時に、クラス型を完成させます。そうであれば、その vtable の新しく宣言されたメンバーを後で TU で修正できます。

于 2013-09-19T16:43:27.490 に答える
0

これについての基準はかなり不明確です。暗黙的なインスタンス化に関する関連セクションは 14.7.1p2 です。

[...] メンバー定義が存在する必要があるコンテキストで特殊化が参照されると、メンバーの特殊化は暗黙的にインスタンス化されます。

「定義が存在する必要がある」は残念ながら完全に定義されていない用語ですが、「odr-used」は少なくともそのサブセットであるという良い議論ができると思います。「odr-used」については、3.2p2 のテキストの大きな壁に次のように書かれています。

純粋でない場合、仮想メンバー関数は ODR 使用されます。

言い換えれば、仮想メンバーは、その単なる存在の美徳 (しゃれは意図されていません) によって必要とされます。

したがって、コンパイラが少なくとも、含まれているクラスをインスタンス化する瞬間に、すべての仮想関数をインスタンス化しようとすることが許可されているという議論を行うことができると思います。それを行うコンパイラは知りません(私の知る限り、そうしないように強制されない限り、それらはすべて翻訳単位の終わりまでインスタンス化を遅らせます)が、あなたのコードは厳密に準拠していないと思います。

于 2013-09-19T15:58:42.733 に答える