I would like to make a class template inheriting class from template parameter, with a set of constructors depending on inherited constructors.
This simple case with optional constructor from int
works fine:
template <typename T>
struct B : T {
using T::T;
B(int) requires( requires{B{};} ) {}
};
struct A {};
B<A> u;
B<A> v(1);
But if I try to conditionally create copy constructor in the same way:
template <typename T>
struct B : T {
using T::T;
B(const B &) requires( requires{B{};} ) {}
};
struct A {};
B<A> u;
B<A> w(u);
it works now only in MSVC. Clang silently evaluates requires{B{};}
to false
making copy constructor unavailable. And GCC prints the error:
<source>:5:28: error: satisfaction value of atomic constraint 'requires{{};} [with T = A]' changed from 'false' to 'true'
5 | B(const B &) requires( requires{B{};} ) {}
| ~~^~~~~~~~~~~~~~~~
Online demo: https://gcc.godbolt.org/z/5K5vn4fEs
Is the first program with B(int)
valid and the second one with copy constructor malformed, and why?
You shouldn't use the class type in a requires
clause in this circular way, because it changes the constraint satisfaction logic, it is essentially undefined behavior, the satisfaction of constraints must not depend on incomplete or circular information about the type itself.
To determine if an atomic constraint is satisfied, the parameter mapping and template arguments are first substituted into its expression. If substitution results in an invalid type or expression in the immediate context of the atomic constraint ([temp.deduct.general]), the constraint is not satisfied. Otherwise, the lvalue-to-rvalue conversion is performed if necessary, and E shall be a constant expression of type bool. The constraint is satisfied if and only if evaluation of E results in true. If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required.
It seems that both are ill formed, no diagnostic required (IFNDR), a warning or error may or may not be issued.