2016-12-29 8 views
6
void f() {} 

namespace test 
{ 
void f(int) {}  
void g() { f(); } // error in gcc 6.2.0 
} 

int main() 
{ 
    test::g(); 
} 

グラム++ -std = C++ 1Z main.cppにでそれをコンパイルし、次のように、出力は次のようになります。gccは、グローバル名前空間でオーバーロードされた関数を隠すのはなぜですか?

main.cpp: In function 'void test::g()': 
main.cpp:9:4: error: too few arguments to function 'void test::f(int)' 
    f(); // error in gcc 
    ^
main.cpp:5:6: note: declared here 
void f(int) {} 

私のコンパイラはGCC 6.2.0です。

グローバル名空間でgccがオーバーロードされた関数を隠すのはなぜですか?これはC++標準に準拠していますか?

答えて

12

グローバル名空間でgccがオーバーロードされた関数を隠すのはなぜですか?これはC++標準に準拠していますか?

はい。つまり、異なるスコープで関数をオーバーロードすることはできません。 unqualified name lookupの規則によれば、f()g()に呼び出すと、名前空間test内にfという名前が見つかる可能性があります。 overload resolutionがその後に起こります(見つけた名前に基づいて)。グローバルネームスペースのf()は、ここでより適切に見えても、まったく考慮されません。非修飾名について

(強調鉱山)

、すなわちスコープ解決演算子の 右側に表示されていない名前である::、後述のように名前ルックアップは スコープを調べ、少なくとも1つの宣言 が見つかるまで、ルックアップは停止し、それ以上のスコープは調べられません。 が検査されます。関数呼び出しをコンパイルするために

は、コンパイラは最初の機能のために、引数依存 のルックアップを伴うことが、 名前検索を実行しなければならない、と関数テンプレートのテンプレート 引数控除を続けてもよいです。 これらのステップで複数の候補の ファンクションが生成された場合、実際に呼び出されるファンクション を選択するために、オーバーロードの解決が実行されます。

あなたはそれらの実際のオーバーロード関数にするために、すなわち、同じスコープに名前を導入するusingを使用することができます。

namespace test 
{ 
    using ::f;  // introduce the name from global namespace 
    void f(int) {}  
    void g() { f(); } // fine 
} 
+2

TL; DR:これは既知のC++気まぐれであり、同じ理由である[基底クラスの派生クラスを非変異体の「オーバーロード」](http://stackoverflow.com/q/1628768/560648)、状況によっては 'Using Base :: foo'が必要です。 –

関連する問題