Повторное объявление явно заданного по умолчанию оператора сравнения делает его неопределенным

В следующей программе struct A имеет оператор сравнения равенства друзей по умолчанию, который переобъявляется снова, чтобы получить указатель на функцию (&operator==):

struct A {
    friend constexpr bool operator ==(const A &, const A &) noexcept = default;
};

static_assert( A{} == A{} ); //if this line is removed the program fails
constexpr bool operator ==(const A &, const A &) noexcept;
static_assert( (&operator==)( A{}, A{} ) );

Все основные компиляторы (GCC, Clang, MSVC) нормально работают с программой. Онлайн-демо: https://gcc.godbolt.org/z/dhcd8esKn

Однако если убрать строку с static_assert( A{} == A{} );, то те же компиляторы начнут отклонять программу с ошибками:

ошибка: 'constexpr booloperator==(const A&, const A&)' используется перед его определением

примечание: неопределенная функция 'operator==' не может использоваться в константе

примечание: сбой был вызван вызовом неопределенной функции или функции, не объявленной «constexpr».

Не могли бы вы объяснить, почему вышеуказанная программа действительна только при наличии static_assert( A{} == A{} ); до operator== передекларирования?

Веселая проблема! Я подозреваю, что экземпляр друга =default не создается до тех пор, пока он не понадобится. Первый static_assert принудительно генерирует его, поэтому у него есть адрес, и, следовательно, второй static_assert может принять его адрес. Но я не языковой юрист, поэтому надеюсь, что кто-нибудь из них вмешается и прояснит эту загадку.

Eljay 19.08.2024 22:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
1
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, это ошибка в протестированных реализациях. EDG принимает программу.

Значение по умолчанию operator== не следует считать неопределенным, поскольку попытка вызвать его в постоянном выражении должна привести к созданию его определения. См. [dcl.fct.def.default]/5

[...] Функция по умолчанию, не предоставленная пользователем (т. е. неявно объявленная или явно заданная по умолчанию в классе), которая не определена как удаленная, определяется неявно, когда она используется odr ([basic.def.odr]) или необходим для постоянной оценки ([expr.const]).

«Необходимо для постоянной оценки» определено в [expr.const]/21

Выражение или преобразование потенциально вычисляется как константа, если оно:

  • выражение с явно константной оценкой,
  • потенциально оцениваемое выражение,
  • непосредственное подвыражение списка инициализации в скобках,
  • выражение формы & cast-expression, которое встречается внутри шаблонной сущности, или
  • потенциально оцениваемое подвыражение ([intro.execution]) одного из вышеперечисленных.

Функция или переменная необходима для постоянного вычисления, если она:

  • функция constexpr, названная выражением, которое потенциально может вычисляться как константа, или
  • потенциально константная переменная, названная потенциально константным вычисленным выражением.

Операнд статического утверждения (&operator==)( A{}, A{} ) явно является выражением, вычисляемым константой. Выражение id operator== внутри него является потенциально вычисляемым подвыражением, поэтому оно потенциально оценивается константой и называет operator==, объявленную в этом примере, которая является функцией constexpr, поэтому эта функция необходима для постоянной оценки.

Обратите внимание, что объявление друга и повторное объявление вне класса объявляют одну и ту же функцию. Таким образом, хотя поиск имени для выражения идентификатора operator== в этом случае находит только повторное объявление вне класса, это выражение идентификатора обозначает функцию, с которой это повторное объявление связывает имя operator==. Таким образом, этого выражения, которое называет функцию, достаточно, чтобы сделать функцию «необходимой для постоянного вычисления», даже если объявление, найденное при поиске, не является определяющим объявлением.

Другие вопросы по теме