6

以下の規格に適合していますか?セクションを引用できますか?

struct A
{
    virtual void func() = 0;
};

struct B
{
    void func(){}
};

struct C : public A, public B
{
    virtual void func(){ B::func(); }
};

VS2010 で奇妙なコンパイラ警告が表示されますが、func最も派生したクラスの の宣言を指しているより複雑なコードですwarning C4505: unreferenced local function has been removed。クラスで宣言された仮想関数がローカルであるとコンパイラが考える理由がわかりません。ただし、より単純な例でその警告を再現することはできません。

編集:

警告の小さな再現ケースを見つけました。関数の隠蔽に関連していると仮定して、間違った道を進んでいたと思います。再現ケースは次のとおりです。

template<typename T>
struct C
{
    int GetType() const;
    virtual int func() const;   // {return 4;}  //  Doing this inline removes the warning <--------------
};

template<typename T>
int C<T>::GetType() const
{
    return 0;
}

template<>
int C<int>::GetType() const
{
    return 12;
}

template<typename T> 
int C<T>::func() const
{
    return 3; 
}

//  Adding the following removes the warning <--------------------
//  template<>
//  int C<int>::func() const
//  {
//      return 4;
//  }

これは単なる VS2010 のバグであると確信しています。

4

3 に答える 3

3

コードは整形式です。 C::funcオーバーライドしますA::funcB::func無関係な関数です。仕様は(10.3 / 2)を読み取ります:

仮想メンバー関数がクラスおよびvfクラスで宣言されている場合、直接または間接的に、と同じ名前、parameter-type-list、cv-qualification、およびref-qualifier(または同じものがない)のメンバー関数が宣言され、次に仮想(そのように宣言されているかどうかに関係なく)であり、111をオーバーライドします。BaseDerivedBasevfBase::vfDerived::vfBase::vf

C::funcと同じ名前A::funcA::func仮想であるため、をC::funcオーバーライドしますA::funcB::funcとは関係ありませんA::func; そのシナリオに明確に対応する言語が仕様に含まれていることを私は知りません。

Visual C ++ 11ベータコンパイラは、このコードに対して警告やエラーを出力しません。

于 2012-05-07T19:54:00.617 に答える
1

通常、仮想関数は、アドレスがvtableに表示される必要があるため、デッドコードとしてリンカーによって削除することはできません。ただし、のvtablestruct Cがデッドコードであると判断された場合(すべてのコンストラクターもデッドコードである場合に発生する可能性があります)、最後に残っている参照も削除できます。

関数が宣言されているためinline、このデッドコード除去の最適化はリンク時まで待つ必要はありません。コンパイラで実行できます。規格によると(セクション7.1.2を参照):

インライン関数は、それがodrで使用されるすべての変換単位で定義され、すべての場合でまったく同じ定義を持つ必要があります(3.2)。[注:インライン関数の呼び出しは、その定義が変換ユニットに表示される前に発生する可能性があります。— end note]関数の定義が、インラインとしての最初の宣言の前に翻訳単位に表示される場合、プログラムの形式が正しくありません。外部リンケージを持つ関数が1つの変換単位でインラインとして宣言されている場合、それが表示されるすべての変換単位でインラインとして宣言されるものとします。診断は必要ありません。外部inlineリンケージを持つ関数は、すべての変換ユニットで同じアドレスを持つ必要があります。関数内のstaticローカル変数はextern inline常に同じオブジェクトを参照します。本体の文字列リテラルextern inline関数は、異なる変換単位の同じオブジェクトです。[注:デフォルトの引数に表示される文字列リテラルは、式がそのインライン関数からの関数呼び出しで使用されるという理由だけで、インライン関数の本体にはありません。— end note]extern inline関数の本体内で定義されたタイプは、すべての翻訳単位で同じタイプです。

コンパイラーは、関数がこの変換ユニットで使用されていないことを判別できる場合、関数を使用するすべての変換ユニットに独自の同一の定義が含まれている必要があることを認識し、コードを生成します。そのため、外部リンケージがまったくないかのように、コード生成をスキップできます。

ただし、警告を生成することは完全に無意味です。これは、誤検知が多数発生するためです(inline関数がodrで使用され、コードが他のコンパイル単位で生成された場合)。

于 2012-05-07T19:58:22.510 に答える
0

私はあなたのためにそれをググさせてください。

function:参照されていないローカル関数が削除されました

指定された関数はローカルであり、モジュールの本体で参照されていません。したがって、関数はデッドコードです。

コンパイラは、このデッド関数のコードを生成しませんでした。

コンパイラは、関数が未使用であると静的に判断したため、その関数のコードを生成せず、役に立たないコードがあることを警告します。通常の未使用の変数警告よりも少し複雑ですが、ほぼ同じ効果があります。デッドコードの臭いです。

于 2012-05-07T19:56:09.427 に答える