Ответ 1
Сравнение указателей определяется в [expr.rel]/3-4:
Сравнение неравных указателей на объекты определяется следующим образом:
- Если два указателя указывают на разные элементы одного и того же массива или на его подобъекты, указатель на элемент с более высоким индексом сравнивается больше.
- Если два указателя указывают на разные нестатические данные членов одного и того же объекта или на подобъекты таких членов, рекурсивно, указатель на более поздний объявленный элемент сравнивается больше, если два члена имеют один и тот же контроль доступа и предоставили свой класс не является объединением.
- В противном случае ни один указатель не сравнится больше другого.
Если два операнда p и q сравниваются равными, p <= q и p >= q оба дают true, а pq - false. В противном случае, если указатель p сравнивается больше, чем указатель q, p >= q, p > q, q <= p и q = p, а q > p все выдают false. В противном случае результат каждого из операторов не указан.
Какие выводы мы можем сделать из этого?
В объекте существует общий порядок указателей того же типа, но порядок указателей на разные объекты или разных подобъектов с различным контролем доступа отсутствует. Это отсутствие общего общего порядка указателей делает is_within_object()
не очень значимым. В тех случаях, когда вы ожидаете возвращения true
, он работает. В тех случаях, когда вы ожидаете возвращения false
, результат этих операторов не указан? Это не очень полезный результат.
Этот сказал, что у нас есть гигантская лазейка для этого в виде [сравнения]:
Для шаблонов
less
,greater
,less_equal
иgreater_equal
специализации для любого типа указателя дают строгий общий порядок, который является согласованным среди этих специализаций и также согласуется с частичным порядком, налагаемым встроенные операторы<
,>
,<=
,>=
.
Таким образом, было бы четко определено следующее:
template<class T>
auto byte_address(T& p) {
return reinterpret_cast<std::byte const*>(std::addressof(p));
}
template<class Object, class Part>
bool is_within_object(Object& object, Part& part)
{
auto first = byte_address(object);
auto last = first + sizeof(Object);
auto p = byte_address(part);
return std::less_equal<std::byte*>{}(first, p) &&
std::less<std::byte*>{}(p, last);
}