I've got the following implementation of the c++ concept move_constructible from cppreference
template<typename _Tp>
concept move_constructible =
    constructible_from<_Tp, _Tp> &&
    convertible_to<_Tp, _Tp>;
I don't get why this works. I presume any type can be converted to itself, so the second requirement is pointless (God, I must be very wrong about something). Also, for the first requirement I would have expected something like constructible_from<_Tp, _Tp&&> to check if the type can be constructed from rvalue-ref (thus, moved).
Please explain how this implementation works.
Most traits/concepts automatically add && to the types of "source" arguments (things that are passed to functions, as in std::is_invocable, or constructed from, as in std::is_constructible).
I.e. constructible_from<A, B> is equivalent to constructible_from<A, B &&> (&& is automatically added to the second argument, but not to the first), and convertible_to<A, B> is equivalent to convertible_to<A &&, B>.
Note that if a type already includes &, adding && to it has no effect. So, while T and T && are equivalent here, T & is not.
This can be inferred from those traits/concepts being defined in terms of std::declval<T>(), which returns T &&.
For the reason why std::declval<T &>() returns T &, see reference collapsing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With