2013-01-16 6 views
12

これはコンパイラのバグですか?演算子が名前空間のスコープ内にあり、グローバルスコープ内に他のものを隠しています

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エラーメッセージは次のとおりです。バグではありません

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

[はい、それはある](http://liveworkspace.org/code/2vreOi$0).... –

+3

はそうは思わないでください。 VC++は同じものを生成します。 – SChepurin

+1

@ KarthikT:あなたのリンクされたコードが "is a bug"をどのようにサポートしているかわかりません。 –

答えて

13

ありません:あなたが行をコメントアウトする場合

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&' 

それがコンパイルされます。 3つの平行な組の演算子が考えられる。メンバー、メンバー以外の演算子、および組み込み関数。

メンバー以外のメンバーは、通常の非修飾+ ADLルックアップによって検索され、すべてのクラスメンバー関数は無視されます。したがって、グローバル演算子は、より語彙的に近いものによって隠されます(そして、介入するメンバー関数は、他の非メンバーを隠していないでしょう)。

の名前の検索後に、の後に、オーバーロードの解決が行われることに注意してください。あなたのケースではoperator++という名前が見つかりましたが、適切なオーバーロードはありません。

バーがグローバルに宣言されていた、および/または(前者の場合)の名前空間空自では他のオペレータ、ADLまたは(後者の場合)通常の非修飾ルックアップがオペレータをドラッグしていた場合は


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

+0

詳細が十分かどうかはわかりません。一致しない場合は、次の囲む名前空間を参照しないでください。 –

+1

@phresnel:しかし、 'operator ++'という名前は 'operator ++'とどのようにマッチしませんか?名前の検索時に関連するのは* name *だけです。 –

+0

@phresnel、実際にはローカル宣言も考慮されます。更新されます... –

7

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

++barには2つの名前検索が実行されます。それはoperator++最初発生を見つけるまで

  • 通常の名前検索は、囲みスコープと名前空間を検索します。この検索は内部で行われるため、グローバル名前空間が最後に検索されます。演算子関数を探すとき、メンバー関数は別々に扱われます(そして、この検索を止めません)。
  • 引数依存のルックアップはnextで起動し、追加のクラスと名前空間を検索しますが、関数の引数に関連するもの(この場合はoperator++)のみを検索します。

質問の例では、通常の検索でasdf::operator++が見つかり、検索が停止します。
引数依存の検索では、enum Barの関連するネームスペースであるため、検索対象の場所にasdf名前空間を追加するだけです。そのため、グローバルoperator++が見つかりません。

グローバルoperator++を名前空間asdfのusing宣言で見つけることができます。

+0

あなたが説明する最初の箇条書きは、クラススコープを考慮しません。つまり、クラスメンバ関数で演算子式を使用しても、同じ名前のメンバ演算子があるにもかかわらず、名前空間スコープ演算子は、非関連の名前空間スコープ内であっても見つけることができます。 –

+0

@ JohannesSchaub-litb:これはC++ 03とC++ 11の間の変更ですか?私はC++ 03の節3.4.1 [basic.lookup.unqual]でそのような例外を見つけることができないからです。 –

+1

ルールは13.3.1.2で指定されています:-) –

1

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

void f(int); 

struct C { 
void f(const C&); 
void g() { 
    f(3); // error: f(const C&) can't be called with argument 3 
}; 
関連する問題