1

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?

1
  • Not sure if first snippet should call operator int, but calling non-constexpr functions in constexpr is indeed allowed only since C++23 Commented Aug 10, 2024 at 16:32

1 Answer 1

2

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 is constexpr-compatible satisfies the requirements for a constexpr function.

Sign up to request clarification or add additional context in comments.

1 Comment

Isn't that a bug in the compilers' implementation of the C++20 standard? Indeed, only after C++23's "P2448R2, Relaxing some constexpr restrictions" problematic snippets get removed/modified but please notice this specific part: "[dcl.constexpr]/6 For a constexpr function or constexpr constructor that is neither defaulted nor a template (...)" where "neither defaulted nor a template" grammatically applies not only to "constexpr constructor" but to "constexpr function" as well. It would be great if someone could confirm or correct me on that :) Thanks in advance!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.