10
void foo(int)
{
}

class X
{
    void foo()
    {
    }

    void bar()
    {
        foo(42);
        // error: no matching function for call to 'X::foo(int)'
        // note: candidate is:
        // note: void X::foo()
        // note:   candidate expects 0 arguments, 1 provided        
    }
};

C++ が free 関数 (正しい署名を持つ唯一の関数) を呼び出せないのはなぜですか?

4

6 に答える 6

12

2 つの識別子は異なるスコープで定義されており、オーバーロードの解決は同じスコープ内の関数にのみ関係するためです。コンパイラは、クラスに があることを検出すると、fooより広いスコープへの上昇を停止する (C++11 §3.4.1/1) ため、free 関数fooは非表示になります。

global を参照するには、修飾名を使用する必要がありますfoo

::foo(42);
于 2012-01-28T12:23:08.833 に答える
5

論理的な理由は一貫性です。

  • 提案に従って、コンパイラfoo(42)::foo(int).
  • しばらくして、に変更X::foo()するとX::foo(int)foo(42)に解決されX::foo(int)ます。これは一貫していません。

これは、類似した名前がある場合に派生クラス関数が基底クラス関数を非表示にする理由でもあります。

このような場合は、2 つの方法で解決できます。

(1) 完全修飾名を付けます (例: ::foo(42))

(2)usingユーティリティを使用します。例えば

void bar()
{
  using ::foo;
  foo(42);
}
于 2012-01-28T12:25:49.380 に答える
2

内側のスコープの名前は、外側のスコープの名前を隠します。それが関数であるか他のものであるか、またはクラスまたは名前空間にいるかどうかは問題ではありません。

名前検索で同じ名前の関数が複数見つかった場合にのみ、オーバーロードの解決が開始され、呼び出しに最適なものを選択しようとします。

于 2012-01-28T12:52:07.893 に答える
1

本当にあなたの質問が好きです。また、次の構文を使用すると言うこともできます。

::foo(42);

しかし、私の意見では、よりエレガントで優れたプログラミングであり、名前空間を設定すると、次のように書くことができます。

namespace MyNameSpace
{
   void foo(int){}

   class X
   {
        void foo(){}

        void bar()
        {
            MyNameSpace::foo(42);
        }
   };
};

Namespacesクラス、オブジェクト、および関数を名前の下にグループ化できるため、これは良いことです。

PS:::foo(42);これは、名前空間がない場合の書き込みの意味を理解するのに役立ちます。

于 2012-01-28T12:45:11.493 に答える
0

私はあなたの質問の理由の部分に答えることができません.言語仕様でその背後にある論理的根拠が何であったかわかりません.

この例でグローバル関数を呼び出すには、:: 構文を使用します。

::foo(42);
于 2012-01-28T12:25:40.033 に答える
0

これは、コンパイラが最初に一致する関数名を探し、戻り値とパラメーターを無視するためです。クラス内では、そこで一致するメンバーを検索しようとします (実際には、ローカル スコープ、関数スコープ、クラス スコープ、名前空間スコープ、グローバル スコープなど、「上向き」のすべてのスコープを検索します。 )。

X::foo最初に一致した名前です。THEN (前ではありません) パラメーターに基づいて正しいオーバーロード (複数の宣言がある場合) を選択しようとします (これが、同じ関数を異なるパラメーターでオーバーロードできるが、異なる戻り値のみをオーバーロードできない理由です)。戻り値 (ある場合)。

于 2012-01-28T12:28:39.627 に答える