Why is the std::derived_from concept implemented with an additional convertibility test that adds cv-qualifiers?
Asked Answered
V

2

20

In the GCC C++20 concepts lib, it has

template<typename _Derived, typename _Base>
    concept derived_from = __is_base_of(_Base, _Derived)
    && is_convertible_v<const volatile _Derived*, const volatile _Base*>;
  1. Why is requiring just __is_base_of(_Base, _Derived) not enough?
  2. What is the need to use const volatile in the test?
Vernavernacular answered 27/1, 2021 at 8:4 Comment(0)
C
15

The behavior of std::derived_from is specified in terms of unambiguous public inheritance

The concept derived_from<Derived, Base> is satisfied if and only if Base is a class type that is either Derived or a public and unambiguous base of Derived, ignoring cv-qualifiers.

Note that this behaviour is different to std::is_base_of when Base is a private or protected base of Derived.

__is_base_of is the compiler intrinsic that is used to implement std::is_base_of. So using it alone would not produce the desired behavior.

So to check the "unambiguous public" part of the requirement, we may check if a pointer to a derived object is implicitly convertible into a pointer to a base object. That's just standard procedure with C++ classes. The pointers are convertible if the classes model an "is-a" relationship, public inheritance and not from multiple bases.

The const volatile addition is to handle the requirement of "ignoring cv-qualifiers". By always adding them, the conversion is legal even if for example _Derived is B const to some A (non-const) _Base. Comparing the pointers as-is would try to convert B const* to A*, and would fail on account of discarded cv-qualifiers.

Cuttler answered 27/1, 2021 at 8:18 Comment(0)
T
8
  1. __is_base_of is not sufficient, because a private base is still a base, and the trait checks for (in words of cppreference):

The concept derived_from<Derived, Base> is satisfied if and only if Base is a class type that is either Derived or a public and unambiguous base of Derived, ignoring cv-qualifiers.

Note that this behaviour is different to std::is_base_of when Base is a private or protected base of Derived.

  1. const volatile is needed because the traits is supposed to ignore cv-qualifiers. A pointer to T implicitly converts to pointer to const volatile T, while to opposite is not true.
Titer answered 27/1, 2021 at 8:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.