6

次のコードがあります。

gcc-3.4、gcc-4.3、Intel コンパイラでは問題なくコンパイルできますが、MSVC9 では失敗します。

MSVC は、「c_traits<C>クラス テンプレート メンバー関数void foo<C>::go(void)を C=short でコンパイルする際に、未定義の型を使用する」と通知します。

このクラスはまったく使用されていないため、コンパイラは未使用のクラスの未使用のメンバー関数をインストールしようとします。

メンバー関数を特殊化するのではなく、クラス foo 全体を特殊化することで、この問題を回避できます。しかし、クラス全体を専門化することは、さまざまな理由で私にとって少し問題があるということです。

大きな疑問:何が正しいのか?

  • 私のコードは間違っていますか? gcc と intel コンパイラは foo を完全にインストールしないため、問題を無視します。
  • コードは正しく、これは未使用のメンバー関数をインストールしようとする MSVC9 (VC 2008) のバグですか?

コード:

class base_foo {
public:
    virtual void go() {};
    virtual ~base_foo() {}
};
template<typename C>
struct c_traits;

template<>
struct c_traits<int> {
    typedef unsigned int_type;
};

template<typename C>
class foo : public base_foo {
public:
    static base_foo *create()
    {
        return new foo<C>();
    }
    virtual void go() 
    {
        typedef typename c_traits<C>::int_type int_type;
        int_type i;
        i=1;
    }
};

template<>
base_foo *foo<short>::create()
{
    return new base_foo();
}

int main()
{
    base_foo *a;
    a=foo<short>::create(); delete a;
    a=foo<int>::create(); delete a;
}
4

2 に答える 2

3

どちらのコンパイラもここにあります。あなたの場合の動作は指定されていません。ISO C++ 14.7.1[temp.inst]/9:

実装は、関数テンプレート、メンバー テンプレート、非仮想メンバー関数、メンバー クラス、またはインスタンス化を必要としないクラス テンプレートの静的データ メンバーを暗黙的にインスタンス化してはなりません。仮想メンバー関数がインスタンス化されない場合、実装がクラス テンプレートの仮想メンバー関数を暗黙的にインスタンス化するかどうかは指定されていません。

この理由は非常に単純です。仮想関数には vtable エントリが必要であり、仮想ディスパッチでは、特定の仮想関数が実際に呼び出されているかどうかをコンパイラが判断するのが難しい場合があります。したがって、ISO C++ では、より小さなコードを生成するために、コンパイラがそのような高度な分析を行うことを許可していますが、それを必要とするわけではありません。そのため、C++ プログラマは、すべての仮想関数が常にインスタンス化されると常に想定する必要があります。

于 2009-11-02T19:41:56.800 に答える
1

未使用の関数の削除は、エラーが発生しているコンパイル時ではなく、リンク時に発生します。MSVC は、コンパイルされているすべてのコンパイル ユニットの中で誰が最終的にそのメソッドを呼び出すかを知らない場合があります。コンパイルが完了し、リンクが発生するまではわかりません。当然、さまざまなコンパイラがこれについてより賢いかもしれませんが、これが起こっているのではないかと思います。

あなたの特定のコンパイラエラーは、前方宣言のみが原因のように聞こえると思います

template<typename C>
struct c_traits;

クラスを完全に指定していません。次のような簡単なことを試しましたか?

template<typename C>
struct c_traits 
{
    // some default/dummy int type
};

これにより、少なくともコンパイラが文句を言うのを止めることができると思います。

編集

これは通常、クラス テンプレートでは正しくありません。クラス テンプレートのメンバー関数は、インスタンス化されていない限り、コンパイルされることは想定されていません (また、その本体のエラーはトリガーされることは想定されていません)。

この場合、テンプレートは次の形式でインスタンス化されます。

 foo<short>

コンパイラはこれを、メソッドの外部リンケージの可能性がある他のクラスとして扱います。外部リンクはテンプレートに適用されないという特別な言語規則は聞いたことがありません...?

于 2009-11-02T18:43:15.867 に答える