Почему концепция std::derived_from реализована с дополнительным тестом конвертируемости, который добавляет квалификаторы cv?

В библиотеке концепций GCC C++20 он имеет

      template<typename _Derived, typename _Base>
    concept derived_from = __is_base_of(_Base, _Derived)
    && is_convertible_v<const volatile _Derived*, const volatile _Base*>;
  1. Почему требуется только __is_base_of(_Base, _Derived)недостаточно?
  2. Что нужно использовать const volatileв тесте?

2 ответа

Поведение std::derived_fromуказывается в терминах однозначного публичного наследования

Концепт derived_from<Derived, Base>удовлетворяется тогда и только тогда, когда тип класса является общедоступной и однозначной базой , игнорируя cv-квалификаторы.

Обратите внимание, что это поведение отличается от того, когда Baseявляется частной или охраняемой базой Derived.

__is_base_ofвстроенная функция компилятора, которая используется для реализации std::is_base_of. Таким образом, его использование само по себе не приведет к желаемому поведению.

Таким образом, чтобы проверить «однозначно общедоступную» часть требования, мы можем проверить, можно ли неявно преобразовать указатель на производный объект в указатель на базовый объект. Это просто стандартная процедура с классами C++. Указатели могут быть преобразованы, если классы моделируют отношение «есть-а», публичное наследование, а не из нескольких баз.

The const volatileдополнение должно обрабатывать требование «игнорировать cv-qualifiers». Всегда добавляя их, преобразование является законным, даже если, например, _Derivedявляется B constнекоторым A(неконстантный) _Base. Сравнение указателей как есть попытается преобразовать B const*к A*, и потерпит неудачу из-за отброшенных cv-квалификаторов.

  1. __is_base_of недостаточно, потому что частная база по-прежнему является базой, а трейт проверяет (словами cppreference):

Концепт derived_from<Derived, Base>удовлетворяется тогда и только тогда, когда Base является типом класса, который является либо Derived, либо общедоступной и однозначной базой Derived, игнорируя cv-qualifiers.

Обратите внимание, что это поведение отличается от std::is_base_of, когда Base является частной или защищенной базой Derived.

  1. const volatileнеобходим, потому что свойства должны игнорировать cv-квалификаторы. Указатель на Tнеявно преобразуется в указатель на const volatile T, в то время как обратное неверно.
Другие вопросы по тегам