После регрессии в GCC 13.3 мне пришлось добавить constexpr
к операторам космического корабля по умолчанию в моей программе, и я заметил некоторые несоответствия в том, как компиляторы обрабатывают некоторый код в режиме C++20. Для краткости кода их можно отобразить в операторе сравнения на равенство ниже.
Пример №1:
struct A {
operator int() const;
};
struct B : A {
constexpr bool operator==(const B &) const = default;
};
это нормально для Clang и MSVC, но GCC с опцией -pedantic-errors
жалуется здесь:
ошибка: вызов функции, отличной от constexpr, 'A::operator int() const' [-Winvalid-constexpr]
Пример №2:
struct A {
bool operator==(const A &) const;
};
struct B : A {
constexpr bool operator==(const B &) const = default;
};
что подходит только для MSVC, в то время как Clang с опцией -pedantic-errors
начинает отклонять также с помощью
ошибка: определение оператора сравнения на равенство по умолчанию, который объявлен constexpr, но вызывает функцию сравнения, отличную от constexpr, является расширением C++23 [-Werror,-Wc++23-default-comp-relaxed-constexpr]
Оба примера кода действительны только для C++23 и недопустимы для C++20?
Это P2448R2, ослабляющее некоторые ограничения constexpr. В частности, для примера OPs снимается следующее ограничение:
(удалено) [dcl.constexpr]/6 Для функции constexpr или конструктора constexpr, который не является ни значением по умолчанию, ни шаблоном, если не существует значений аргументов, таких, что вызов функции или конструктора мог бы быть вычисленным подвыражением основного константного выражения, или, для конструктора, вычисленное подвыражение полного выражения инициализации некоторого объекта, инициализируемого константой ([basic.start.static]), программа имеет неверный формат, диагностика не требуется.
А также устраняется концепция совместимости с constexpr для функций сравнения по умолчанию:
(удалено) [class.compare.default]/4 Функция сравнения по умолчанию является constexpr-совместимой, если она удовлетворяет требованиям для функции constexpr ([dcl.constexpr]) и разрешение перегрузки не выполняется при определении того, следует ли удалить функцию, что приводит к полезный кандидат, который не является функцией constexpr.
(изменено/добавлено) [dcl.fct.def.default]/3 Функция с явным значением по умолчанию, которая не определена как удаленная, может быть объявлена constexpr или consteval только в том случае, если он совместим с constexpr ([специальный], [класс.сравнить.по умолчанию]). Функция, явно дефолтная для своего первое объявление неявно встроено ([dcl.inline]) и неявно constexpr ([dcl.constexpr]), если это constexpr-совместимый удовлетворяет требованиям для функция constexpr.
Не уверен, что первый фрагмент должен вызывать
operator int
, но вызов функций, не являющихся constexpr, вconstexpr
действительно разрешен только начиная с C++23.