After a regression in GCC 13.3, I had to add constexpr
to defaulted spaceship operators in my program, and observed some discrepancies in how compilers treat some code in C++20 mode. These can be shown on equality comparison operator for the sake of code brevity below.
Example #1:
struct A {
operator int() const;
};
struct B : A {
constexpr bool operator==(const B &) const = default;
};
which is ok for Clang and MSVC, but GCC with -pedantic-errors
option complains here:
error: call to non-'constexpr' function 'A::operator int() const' [-Winvalid-constexpr]
Example #2:
struct A {
bool operator==(const A &) const;
};
struct B : A {
constexpr bool operator==(const B &) const = default;
};
which ok only for MSVC, while Clang with -pedantic-errors
option starts rejecting it as well with the
error: defaulted definition of equality comparison operator that is declared constexpr but invokes a non-constexpr comparison function is a C++23 extension [-Werror,-Wc++23-default-comp-relaxed-constexpr]
Are both code examples valid only in C++23 and not valid in C++20?
This is P2448R2, Relaxing some constexpr restrictions. Particularly, for OPs example, it removes the following restriction:
(removed) [dcl.constexpr]/6 For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, an evaluated subexpression of the initialization full-expression of some constant-initialized object ([basic.start.static]), the program is ill-formed, no diagnostic required.
And also removes the concept of constexpr-compatible for defaulted comparison functions:
(removed) [class.compare.default]/4 A defaulted comparison function is constexpr-compatible if it satisfies the requirements for a constexpr function ([dcl.constexpr]) and no overload resolution performed when determining whether to delete the function results in a usable candidate that is a non-constexpr function.
(modified/added) [dcl.fct.def.default]/3
An explicitly-defaulted function that is not defined as deleted may be declared constexpr or consteval only if it is constexpr-compatible ([special], [class.compare.default]). A function explicitly defaulted on its first declaration is implicitly inline ([dcl.inline]), and is implicitly constexpr ([dcl.constexpr]) if it isconstexpr-compatible satisfies the requirements for a constexpr function.