15

N3337、「ワーキング ドラフト、プログラミング言語 C++ の標準」では、13.3.1.2 節の次の例を示しています。10:

struct A { };
void operator + (A, A);
struct B {
  void operator + (B);
  void f ();
};
A a;
void B::f() {
  operator+ (a,a);   // error: global operator hidden by member
  a + a;             // OK: calls global operator+
}

ただし、これは単なるメモです。

注: 次の例に示すように、式内の演算子の検索規則は、関数呼び出し内の演算子関数名の検索規則とは異なります。

私の質問は、標準のどこで、これが起こらなければならないことであると言っているのですか?

私が知る限り、条項13.3.1.2によると、p。2、演算子式は演算子関数呼び出しに変換されます。では、上記の例では、なぜ、どのように違いがあるのでしょうか?

編集:

問題を調べたところ、p を見落としていたのではないかと思います。3 と p.6 の同じ節で、演算子を検索するときにグローバル候補とメンバー候補が同等に考慮されると述べられています (したがって、注記にあるように、検索ルールは異なります)。ただし、この件に関する私の調査は、GCC 4.8 と Clang で同じようにコンパイルされる次の例に端を発しています。

struct X {};  struct Y {};

void operator+(X, X) { }
void operator+(X, Y) { }

void test() {
  void operator+(X, X);
  X x; Y y;

  x + x;  // OK
  x + y;  // OK

  operator+(x, y);  // error
  operator+(x, x);  // OK
}

演算子関数が直接呼び出された場合にブロック スコープ宣言によるシャドーイングが発生するのに、演算子式によって呼び出された場合には発生しないのはなぜですか?

GCC からのエラーは次のとおりです。

operators-main-ss.cpp: In function ‘void test()’:
operators-main-ss.cpp:13:17: error: could not convert ‘y’ from ‘Y’ to ‘X’
   operator+(x, y);  // error
                 ^

そしてここでClangから:

operators-main-ss.cpp:13:16: error: no viable conversion from 'Y' to 'X'
  operator+(x, y);  // error
               ^
operators-main-ss.cpp:1:8: note: candidate constructor (the implicit copy constructor) not viable: no
      known conversion from 'Y' to 'const X &' for 1st argument;
struct X {};  struct Y {};
       ^
operators-main-ss.cpp:7:22: note: passing argument to parameter here
  void operator+(X, X);
                     ^

あるケースではブロック宣言がグローバル名をシャドーし、他のケースではシャドーしないコンパイラは正しいですか?

4

3 に答える 3

4

元の質問:

あなたの結論は正しいです。

operator+(a, a);は単純な関数呼び出しであるため、コンパイラは標準の順序で潜在的な一致を検索し、メンバー関数を見つけて、それ以上検索しません。メンバー関数が一致せず、式の形式が正しくありません。

a + a;13.3.1.2 p3 で定義されているように、わずかに異なるルール セットを使用します。最初に、可能なオーバーロードのセットが から生成されA::operator+(a)ます。次に、可能なオーバーロードのリストが標準の非修飾ルックアップから生成されますが、メンバー関数は無視されます。次に、組み込み演算子のリストが作成されます。これら 3 つのリストは、最適な一致を決定するために使用されます。通常、非修飾ルックアップは、何かが見つかった場合、最初のステップの後に停止します。これが、通常は失敗する場所でこれが機能する理由です。

質問パート 2:

理論的には、これは同じはずです。メンバー関数は関与せず、組み込み演算子は無関係であるため、それらはすべて標準の非修飾ルックアップになります。標準には、それらが何らかの形で異なるべきであることを示唆するものは何も見つかりません。「存在する」ことを除いて、標準でブロックスコープ関数宣言についてあまり言及されていません。結局のところ、それらはほとんどが C の遺物にすぎません。また、これが機能するかどうかについて何らかの方法で述べている標準の特定のルールも見当たりません。標準では、名前の検索に同じ方法を使用しているため、両方が機能するか、両方が失敗することx + yを非常に強く示唆しています。operator+(x, y)

また、ネストされた関数宣言の有効な使用例をまだ見つけていません。

于 2012-12-14T01:53:31.823 に答える
1

あるケースではブロック宣言がグローバル名をシャドーし、他のケースではシャドーしないコンパイラは正しいですか?

どちらのコンパイラも間違っているという結論に達しました。私x + y;も失敗するべきだと思います。13.3.1.2p3 はそれを明確に述べています:

非メンバー候補のセットは、すべてのメンバー関数が無視されることを除いて、非修飾関数呼び出し (3.4.2) での名前検索の通常の規則に従って、式のコンテキストで operator@ の非修飾検索の結果です。

その結果、あなたの例ではx + y;との間に違いはないはずです。Commeau onlineは、コードで次のエラーを生成します。operator+(x, y);

"ComeauTest.c", line 11: error: no operator "+" matches these operands
            operand types are: X + Y
    x + y;  // OK
      ^
"ComeauTest.c", line 13: error: no suitable user-defined conversion from "Y"
 to "X"
          exists
    operator+(x, y);  // error
于 2012-12-14T03:01:20.200 に答える
0

ご質問についてその2

これは、ADL $3.4.2 に関する標準の c++11 からの引用です。

X を非修飾ルックアップ (3.4.1) によって生成されたルックアップ セットとし、Y を引数依存ルックアップ (次のように定義) によって生成されたルックアップ セットとします。Xが含まれている場合

  • クラスメンバーの宣言、または
  • using 宣言ではないブロック スコープの関数宣言、または
  • 関数でも関数テンプレートでもない宣言

Y は空です。

...

それはあなたの質問に答えるようです

于 2013-10-05T14:13:32.933 に答える