Constexpr проверяет, изменяет ли значение указателя static_cast указателей между двумя иерархически связанными типами

#c #language-lawyer #static-cast

#c #язык-юрист #статическое приведение

Вопрос:

Для какой-то специализированной вещи, подобной распределителю, которую я реализую, я хотел бы потребовать, чтобы все объекты, которые будут сохранены, использовали общий базовый класс в качестве своего первого подобъекта. Это позволяет мне сохранить один указатель общего базового класса как индикатор начала объекта, а также восстановить доступ к исходному объекту с помощью static_cast , предполагая, что у меня есть какой-то способ узнать тип исходного объекта.

В частности, я хотел бы, чтобы следующее равенство всегда выполнялось для любого указателя ptr на тип Base , предполагая отсутствие виртуального наследования между Derived и Base .

 reinterpret_cast<char *>(static_cast<Derived*>(ptr)) == reinterpret_cast<char *>(ptr)
  

Я предполагаю, что это уравнение выполняется либо для всех допустимых указателей данной иерархии классов,
либо оно не выполняется ни для одного допустимого указателя данной иерархии классов. Это правильно?

Следовательно, эту проверку должно быть возможно выполнить во время компиляции, даже не зная значения времени выполнения ptr . Итак, есть ли constexpr способ проверить static_cast , изменяет ли значение указателя между двумя связанными типами? Приведенное выше равенство кажется неприемлемым, поскольку я не нашел способа constexpr для создания тестового указателя.

Комментарии:

1. я не понимаю вопроса. Если все они наследуются от общего базового класса, то зачем все это нужно? И даже с приведениями, почему нет dynamic_cast ?

2. ваш вопрос: как определить, является ли Base первый базовый класс каким-либо типом T ? ?

3. мой вопрос заключается в том, как определить во время компиляции, будет ли данное равенство истинным или ложным. Я почти уверен, что это то же самое, что определять во время компиляции, проходит ли путь от T до Base только через первые базовые классы по иерархии.

4. dynamic_cast не вариант, потому что это для небольших встроенных систем без RTTI.

5. Это будет работать только для стандартных классов компоновки. Затем en.cppreference.com/w/cpp/types/is_layout_compatible с базовым классом могло бы помочь.

Ответ №1:

Вы спрашиваете о взаимопревращаемости указателей. Существует связанная черта std::is_pointer_interconvertible_base_of , которая еще не реализована в gcc и clang. См. Также Статью и выпуск. Типы, преобразуемые между указателями, имеют один и тот же адрес, и их указатели могут быть преобразованы между с reinterpret_cast помощью .

Я предполагаю, что это уравнение выполняется либо для всех допустимых указателей данной иерархии классов, либо оно не выполняется ни для одного допустимого указателя данной иерархии классов. Это правильно?

Как вы уже отмечали, виртуальное наследование препятствует этому, но также и невыполнение стандартных критериев компоновки. Если Derived имеет несколько базовых классов и Base не является первым, он завершается с ошибкой.

Вопрос не мотивирует требование иметь один и тот же адрес. Если это не является обязательным требованием, static_cast преобразование из Derived в Base и понижение из Base в Derived будет работать только до тех пор, пока отношение наследования не является виртуальным, однозначным и общедоступным.

Комментарии:

1. Спасибо за подробный ответ! Причина требования заключается в том, чтобы разрешить использовать один указатель как ссылку на объект, так и разделитель (с одной стороны) объема памяти объекта — для уменьшения нагрузки на память.