At the cppref page on the concept std::default_initializable
, I saw the following code:
template<class T>
concept default_initializable =
std::constructible_from<T> && requires { T{}; ::new T; };
I think requires { T{}; ::new T; }
is enough.
Why did it add redundant std::constructible_from<T>
?
First, as pointed out in the comments, constructible_from<T>
is not equivalent to either of these expressions: T{}
or new T
. It uses is_constructible_v<T>
, which would use T t();
.
It also includes destructible<T>
. Which your requires
expression does not test for. As such, default_initializable
requires that the type can be destroyed as well as default initialized.
Also, concepts are not constant expression boolean values. They get to have relationships to other concepts. One concept can "subsume" another, which means that it is more constrained than the other. So if there are two constrained templates of the same name (overloaded functions), and the given type is permitted by both contraints, the more constrained template is chosen.
default_initializable
uses constructible_from
in order to allow it to "subsume" constructible_from
. It is more constrained than constructible_from
.
This would not happen if constructible_from
was not there. Subsumption relationship are based on the use of exactly equivalent atomic constraint expressions. While part of requires { T{}; ::new T; ::new T(); }
might be behaviorally similar to constructible_from
, as far as the atomic constraint expressions are concerned, they are entirely distinct.