Сравнение C ++ 20: предупреждение о неоднозначном обращенном операторе - PullRequest
6 голосов
/ 25 февраля 2020

Рассмотрим этот действительный пример C ++ 17:

struct A {
   bool operator==(const A&);
};


int main() {
   return A{} == A{};
}

Когда скомпилировано в clang с -std = c ++ 20, это дает :

<source>:7:15: warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'A' and 'A') to be ambiguous despite there being a unique best viable function [-Wambiguous-reversed-operator]

   return A{} == A{};

          ~~~ ^  ~~~

<source>:2:9: note: ambiguity is between a regular call to this operator and a call with the argument order reversed

   bool operator==(const A&);

Означает ли это предупреждение, что C ++ 20 запрещает использовать типичный оператор сравнения для сравнения двух объектов одного типа? Какова правильная альтернатива? Ожидается ли изменение ситуации в будущих проектах?

Ответы [ 2 ]

6 голосов
/ 25 февраля 2020

Означает ли это предупреждение, что C ++ 20 запрещает использовать типичный оператор сравнения для сравнения двух объектов одного типа? Какова правильная альтернатива? Ожидается ли изменение ситуации в будущих черновиках?

Это на самом деле не типичный оператор сравнения, это уже своего рода неправильно - поскольку он допускает только объект const на одной стороне (ваш тип A также не удовлетворит новую концепцию equality_comparable, даже без изменений в языке).

Вы должны написать это так:

struct A {
   bool operator==(const A&) const;
//                          ^^^^^^
};

Это последнее правило для C ++ 20.

Проблема c заключается в том, что в C ++ 20 операторы сравнения добавляют новое понятие переписанных и перевернутых кандидатов. Так что поиск выражения a == b также в конечном итоге приведет к сопоставлению операторов, подобных b == a. В типичном случае это означает, что вам нужно писать меньше операторов, поскольку мы знаем, что равенство коммутативно.

Но если у вас есть несоответствие констант, то произойдет следующее: вы получите следующие два кандидата:

bool operator==(/* this*/ A&, A const&); // member function
bool operator==(A const&, /* this*/ A&); // reversed member function

С двумя аргументами типа A. Первый кандидат лучше по первому аргументу, а второй кандидат лучше по второму аргументу. Ни один из кандидатов не лучше другого, а потому и неоднозначен.

3 голосов
/ 25 февраля 2020

Общим правилом разрешения перегрузки является то, что каждый тип аргумента должен быть отдельно как минимум так же близко к типу параметра для выбранной функции, как и к типу параметра для любой другой:

struct A {A(int);};
void f(long,int);   // #1
void f(int,A);      // #2
void g() {f(0,0);}  // error: ambiguous

Гораздо худшее преобразование для второго аргумента для # 2 не компенсирует преобразование intlong для первого аргумента.

В C ++ 20 различные правила переписывания были добавлены, чтобы избавить от необходимости писать так много, но идентичных перегрузок операторов сравнения. В то время как тривиальные неоднозначности между написанными от руки «обращенными кандидатами» и идентичными сгенерированными компилятором правилами обрабатываются правилами t ie -breaker , которые предпочитают реальные функции, этого (опять же) недостаточно, чтобы восполнить худшее преобразование для любого аргумента.

Операторы сравнения, написанные тщательно в соответствии с принятой (C ++ 17) практикой, будут очень редко сталкиваться с этим, но сомнительные подписи, подобные этой (с асимметрией * 1019) * const) вполне может быть проблематично c (по-новому). Надеемся, что будет найдено больше ошибок, чем вызвано этим расширением.

...