2012-05-07 22 views
6

次の規格は適合していますか?セクションを引用できますか? warning C4505: unreferenced local function has been removed仮想関数は、基本クラスの同じ名前の非仮想関数をオーバーライドしますか?

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

struct B 
{ 
    void func(){} 
}; 

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

私は、派生クラスで最もfuncの宣言を指していると等価が、より複雑なコードでVS2010での奇妙なコンパイラの警告を取得しています。私は、コンパイラがクラス内で宣言された仮想関数がローカルであると考える理由を知らない。しかし私は簡単な例でその警告を再現することはできません。

編集:

私は警告のための小さなREPROケースを考え出しました。私はそれが関数の隠蔽に関連していると仮定して、間違った経路を辿っていたと思う。

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のバグであるかなり確信している:ここにREPROケースです。

+4

"同等ですがもっと複​​雑なコードでは...簡単な例で警告を再現できません"。それから彼らはおそらく同等ではありません。 –

+0

上記のコードでは、あなたがVS2010で話す警告は出ません。意味的に間違っていることは何もありませんが、デザインの選択は私にとって奇妙です。 – AJG85

+0

私はまだその警告を再現する方法を理解しようとしています - 私は/ときに編集します。 – David

答えて

3

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

仮想メンバ関数vfBase、同じ名前を持つメンバ関数vf、パラメータから直接または間接的に派生クラスBaseおよびクラスDerivedで宣言された場合(実際には宣言されているかどうかにかかわらず)が宣言されていれば、Derived::vfも宣言されているかどうかにかかわらず、Base::vfをオーバーライドします。 A::funcA::funcしたがって、C::funcオーバーライドA::func仮想そのまま

C::funcは、同じ名前を有しています。 B::funcA::funcとは関係ありません。私は、そのシナリオに明示的に対処する仕様に言語があることは知らない。

Visual C++ 11 Betaコンパイラは、このコードに対して警告またはエラーを発行しません。

0

Let me google it for you.

function:参照されていないローカル関数は、指定された機能は、ローカルおよびモジュールの本体で参照ない

が除去されています。したがって、関数はデッドコードです。

コンパイラはこの機能不全のコードを生成しませんでした。

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

+1

私はGoogleに感謝しました。これは 'LOCAL'関数にのみ意味があります。私はコンパイラが関数が未使用であるかどうかをどのように知っているのか見ることさえできません。それはリンカでなければならないでしょう。その場合、リンカの警告になります。これまでにクラス内の未使用の仮想関数に関する警告を見たことがありますか?これまで? – David

+0

@Dave:この関数は(暗黙的に) 'inline'宣言されています。つまり、他のコンパイル単位が使用されていれば、他のコンパイル単位に記述する必要があります。したがってコンパイラは関数への外部参照を心配する必要はなく、ローカルとして扱うことができます。 –

+0

Ahhh。面白い。しかし、しかし、それは仮想です - 本当にそれが呼び出されるかどうかはそのレベルで解決できますか?実際、私は以前の姿勢に戻っています:あなたは、テンプレートクラスにあるので、呼び出されずにインラインであるアクセッサやミューテータを使用して、テンプレートクラスについて、この警告を独自のコードで見たことがありますか?それは同じケースの権利ですか? – David

1

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

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

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

コンパイラは、関数を決定することができる場合にこの翻訳単位を使用されることはありません、それは機能を使用しない任意の翻訳単位は、独自の同一の定義が含まれている必要がありますし、コードを生成することを知っています。だから、まるで外部のリンケージを持っていないかのようにコード生成をスキップすることができます。

しかし、多くの誤検出があります(inline関数が使用され、他のコンパイル単位でコードが生成された場合)ので、警告を生成することは全く意味がありません。

関連する問題