Правила поиска операторов в С++ 11

N3337, "Рабочий проект, стандарт для языка программирования С++", приведен ниже в разделе 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, стр. 2, операторные выражения преобразуются в вызовы функций оператора. Итак, почему и как должна быть разница в приведенном выше примере?

Изменить:

Изучив проблему, я думаю, что, возможно, я упустил п. 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
                 ^

И вот от Клана:

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);
                     ^

Правильны ли компиляторы, чтобы объявление блока отображало глобальное имя в одном случае, а не другое?

Ответы

Ответ 1

Правильны ли компиляторы, чтобы объявление блока было теневым глобальное имя в одном случае, но не другое?

Я пришел к выводу, что оба компилятора ошибочны. Я считаю, что x + y; тоже потерпит неудачу. 13.3.1.2p3 ясно указывает:

Набор кандидатов, не являющихся членами, является результатом неквалифицированного поиск оператора @в контексте выражения в соответствии с обычные правила поиска имен в неквалифицированных вызовах функций (3.4.2) за исключением того, что все функции-члены игнорируются.

В результате в вашем примере не должно быть разницы между x + y; и operator+(x, y);. Commeau online выдает следующие коды кода:

"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

Ответ 2

Ваш оригинальный вопрос:

Ваше заключение верное.

operator+(a, a); - это простой вызов функции, поэтому компилятор ищет возможные совпадения в стандартном порядке, находит функцию-член и никогда не смотрит дальше. Функция-член не соответствует, и выражение плохо сформировано.

a + a; использует несколько иной набор правил, как определено в 13.3.1.2 p3. Сначала набор возможных перегрузок создается из A::operator+(a). Затем список возможных перегрузок создается из стандартного неквалифицированного поиска, но функции-члены игнорируются. Затем создается список встроенных операторов. Эти 3 списка затем используются для определения наилучшего соответствия. Обычно неквалифицированный поиск останавливается после первого шага, если он найдет что-то, поэтому он работает там, где он обычно терпит неудачу.

Часть вопроса 2:

В теории это должно быть одинаково. Не задействованы никакие функции-члены и встроенные операторы, поэтому они должны привести к стандартному неквалифицированному поиску. Я не могу найти ничего в стандарте, чтобы предположить, что они должны быть разными. Я не вижу особого упоминания о объявлениях функций области блока в стандарте, кроме "они существуют". В основном это реликвия C. Я также не вижу каких-либо конкретных правил в стандарте, которые так или иначе говорят о том, должно ли это работать или нет. Стандарт очень сильно указывает, что x + y и operator+(x, y) должны либо работать, либо обе сбой, поскольку оба они используют один и тот же метод для поиска имени.

Мне также еще предстоит найти допустимый прецедент для объявлений вложенных функций.

Ответ 3

относительно вашего вопроса часть 2

вот цитата из стандартного С++ 11 относительно ADL $3.4.2:

Пусть X - это набор поиска, созданный неквалифицированным поиском (3.4.1), и Y - это набор поиска, созданный зависимым от аргумента поиска (определяется следующим образом). Если X содержит

  • объявление члена класса или
  • объявление функции блока-области, которое не является декларацией использования, или
  • объявление, которое не является ни функцией, ни шаблоном функции

тогда Y пусто.

...

кажется, что отвечает на ваш вопрос