Reputation: 21291
In the following program, struct A
has default friend equality comparison operator, which is redeclared again to get the pointer of the function (&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{} ) );
All major compilers (GCC, Clang, MSVC) are fine with the program. Online demo: https://gcc.godbolt.org/z/dhcd8esKn
However if the line with static_assert( A{} == A{} );
is removed, then the same compilers start rejecting the program with the errors:
error: 'constexpr bool operator==(const A&, const A&)' used before its definition
note: undefined function 'operator==' cannot be used in a constant
note: failure was caused by call of undefined function or one not declared 'constexpr'
Could you please explain why above program is valid only in presence of static_assert( A{} == A{} );
before operator==
redeclaration?
Upvotes: 4
Views: 138
Reputation: 119239
This seems to be a bug in the implementations tested. EDG accepts the program.
The defaulted operator==
should not be considered undefined because attempting to call it in a constant expression should cause its definition to be generated. See [dcl.fct.def.default]/5
[...] A non-user-provided defaulted function (i.e., implicitly declared or explicitly defaulted in the class) that is not defined as deleted is implicitly defined when it is odr-used ([basic.def.odr]) or needed for constant evaluation ([expr.const]).
"Needed for constant evaluation" is defined in [expr.const]/21
An expression or conversion is potentially constant evaluated if it is:
- a manifestly constant-evaluated expression,
- a potentially-evaluated expression,
- an immediate subexpression of a braced-init-list,
- an expression of the form
&
cast-expression that occurs within a templated entity, or- a potentially-evaluated subexpression ([intro.execution]) of one of the above.
A function or variable is needed for constant evaluation if it is:
- a constexpr function that is named by an expression that is potentially constant evaluated, or
- a potentially-constant variable named by a potentially constant evaluated expression.
The operand of the static assertion, (&operator==)( A{}, A{} )
, is a manifestly constant-evaluated expression. The id-expression operator==
within it is a potentially-evaluated subexpression, so it is potentially constant evaluated, and it names the operator==
declared in this example, which is a constexpr function, so that function is needed for constant evaluation.
Note that the friend declaration and the out-of-class redeclaration declare the same function. So, although name lookup for the id-expression operator==
finds only the out-of-class redeclaration in this case, that id-expression denotes the function to which that redeclaration binds the name operator==
. So this expression that names the function is sufficient to make the function "needed for constant evaluation" even though the declaration found by the lookup is not the defining declaration.
Upvotes: 4