Почему концепция 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*>;
- Почему требуется только
__is_base_of(_Base, _Derived)
недостаточно? - Что нужно использовать
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-квалификаторов.
- __is_base_of недостаточно, потому что частная база по-прежнему является базой, а трейт проверяет (словами cppreference):
Концепт
derived_from<Derived, Base>
удовлетворяется тогда и только тогда, когда Base является типом класса, который является либо Derived, либо общедоступной и однозначной базой Derived, игнорируя cv-qualifiers.Обратите внимание, что это поведение отличается от std::is_base_of, когда Base является частной или защищенной базой Derived.
-
const volatile
необходим, потому что свойства должны игнорировать cv-квалификаторы. Указатель наT
неявно преобразуется в указатель наconst volatile T
, в то время как обратное неверно.