13

これはコンパイラのバグですか?

template <typename T>
T& operator++(T& t)
{
    return t;
}

namespace asdf {

enum Foo { };
enum Bar { };

Foo& operator++(Foo& foo);

void fun()
{
    Bar bar;
    ++bar;
}

} // end namespace asdf

int main()
{
    return 0;
}

GCC 4.7 エラー メッセージは次のとおりです。

error: no match for 'operator++' in '++bar'
note: candidate is:
note: asdf::Foo& asdf::operator++(asdf::Foo&)
note: no known conversion for argument 1 from 'asdf::Bar' to 'asdf::Foo&'

次の行をコメントアウトするとコンパイルされます。

Foo& operator++(Foo& foo);
4

3 に答える 3

14

いいえ、それはバグではありません。考慮される演算子の 3 つの並列セットがあります。メンバー、非メンバー演算子、およびビルトイン。

非メンバーのものは、すべてのクラス メンバー関数を無視して、通常の非修飾 + ADL 検索によって検索されます。したがって、グローバル演算子は、レキシカルなより近いものによって隠されます (そして、介在するメンバー関数は他の非メンバーを隠しません)。

オーバーロードの解決は、名前のルックアップ1の後に行われることに注意してください。あなたの場合、名前は見つかりましたが、適切なオーバーロードがありませんでした。operator++

Bar がグローバルに宣言されている場合、および/または名前空間 asdf 内の他の演算子の場合、ADL (前者の場合) または通常の非修飾ルックアップ (後者の場合) は演算子をドラッグします。


1 : Overload resolution (...) takes place after name lookup has succeeded.(C++ 標準)

于 2013-01-16T08:58:02.917 に答える
8

いいえ、これはコンパイラのバグではありません。

式に対して実行される 2 つの名前検索があります++bar

  • 通常の名前検索では、最初operator++. この検索は裏返しに機能するため、グローバル名前空間が最後に検索されます。演算子関数を検索する場合、メンバー関数は個別に処理されます (この検索を停止しないでください)。
  • 引数依存のルックアップが次に開始され、追加のクラスと名前空間が検索されますが、関数の引数に関連するもののみが検索されます (operator++この場合)。

質問の例では、通常のルックアップが検索asdf::operator++を停止します。引数依存のルックアップは、検索する場所に名前空間を
追加するだけです。これは に関連付けられている名前空間だからです。そのため、グローバルが見つかりません。asdfenum Baroperator++

operator++namespace で using 宣言を使用して、グローバルを見つけることができますasdf

于 2013-01-16T09:03:57.057 に答える
1

オーバーロードは、同じスコープで定義された名前にのみ適用されます。コンパイラが一致する名前を見つけると、見つかった名前が使用できないものに適用される場合でも、外側のスコープは検索されません。これは演算子とは関係ありません。コードが operator++ を使用するのと同じ方法で関数名を使用すると、同じエラーが発生します。例えば:

void f(int);

struct C {
void f(const C&);
void g() {
    f(3); // error: f(const C&) can't be called with argument 3
};
于 2013-01-16T12:06:37.927 に答える