2016-08-11 3 views
2

В этом question цитируется стандарт C++, чтобы продемонстрировать, что выравнивание и размер CV-типов должны быть такими же, как и для эквивалентного типа, отличного от CV. Это кажется очевидным, потому что мы можем косвенно лить объект типа T в const T& с использованием static_cast или reinterpret_cast.Сводные данные и литьевые данные

Однако предположим, что у нас есть два типа, которые имеют одинаковые типы переменных-членов, за исключением того, что у одного есть все переменные-члены const, а другие нет. Такие, как:

typedef std::pair<T, T> mutable_pair; 
typedef std::pair<const T, const T> const_pair; 

Здесь, стандарт не позволяет нам производить const_pair& из экземпляра mutable_pair. То есть, мы не можем сказать:

mutable_pair p; 
const_pair& cp = reinterpret_cast<const_pair&>(p); 

Это даст неопределенное поведение, так как она не указана в качестве действительного использования reinterpret_cast в стандарте. Тем не менее, по-видимому, нет причин, концептуально, почему это нельзя допускать.

Итак ... зачем кому-то это нужно? Вы всегда можете просто сказать:

const mutable_pair& cp = p; 


Ну, вы мощь помощь в случае, если вы хотите только один член будет const квалификацию. Такие как:

typedef std::pair<T, U> pair; 
typedef std::pair<const T, U> const_first_pair; 

pair p; 
const_first_pair& cp = reinterpret_cast<const_first_pair&>(p); 

Очевидно, что это по-прежнему неопределенное поведение. Тем не менее, поскольку CV квалифицированные типы должны иметь одинаковый размер и выравнивание, нет концептуальной причины, по которой это должно быть неопределенным.

Итак, есть ли причина, по которой стандарт не позволяет? Или это просто вопрос, что стандартный комитет не думал об этом прецеденте?


Для тех, интересно, какого рода использования это может иметь: в моем конкретном случае, я побежал в прецеденте, где это было бы очень полезно, чтобы иметь возможность бросить std::pair<T, U> к std::pair<const T, U>&. Я реализовал специализированную структуру сбалансированных древовидных данных, которая обеспечивает поиск по ключевому слову log(N), но внутренне хранит несколько элементов на узел. Процедуры find/insert/rebalance требуют внутренней перетасовки элементов данных. (Структура данных известна как T-tree.) Поскольку внутренняя перетасовка элементов данных отрицательно влияет на производительность, вызывая множество бесчисленных конструкторов копий, полезно реализовать внутреннюю перетасовку данных, чтобы по возможности использовать конструкторы перемещения.

К сожалению ... Я также хотел бы быть в состоянии предоставить интерфейс, который отвечает на C++ стандартных требований к AssociativeContainer, что требует value_type из std::pair<const Key, Data>. Обратите внимание на const. Это означает, что отдельные пары объектов не могут быть перемещены (или, по крайней мере, ключи не могут). Они должны копировать, поскольку ключ хранится как объект const.

Чтобы обойти это, я хотел бы иметь возможность хранить элементы внутри себя как изменяемые объекты, но просто бросать ключ в ссылку const, когда пользователь обращается к ним через итератор. К сожалению, я не могу отличить std::pair<Key, Data> от std::pair<const Key, Data>&.И я не могу предоставить какое-то обходное решение, которое возвращает класс-оболочку или что-то в этом роде, потому что это не соответствует требованиям для AssociativeContainer.

Отсюда этот вопрос.

Так что, учитывая, что требования к размеру и выравниванию квалифицированного типа CV должны быть такими же, как у эквивалентного эквивалента, отличного от CV, существует ли какая-либо концептуальная причина, почему такой отбор не допускается? Или это просто то, о чем не думали стандартные авторы?

+1

«мы можем неявно отбрасывать объект типа' T' в 'const T &', используя 'static_cast' или' reinterpret_cast'. " ... Whut? Если вам нужно набрать операцию трансляции, то она по определению не является неявным. Во всяком случае, это именно то, что для 'const_cast', а не для других; Конечно, они будут работать, но почему бы не использовать семантически релевантное ключевое слово? –

ответ

4

Наличие типа параметра шаблона не означает, что у вас не будет разных выравниваний, содержимое класса может быть изменено, например, посредством специализации или метапрограммирования шаблонов. Рассмотрите:

template<typename T> struct X { int i; }; 
template<typename T> struct X<const T> { double i; }; 

template<typename T> struct Y { 
    typename std::conditional<std::is_const<T>::value, int, double>::type x; 
}; 
+0

Простой ответ заключается в том, что различные аргументы шаблона создают разные и несовместимые типы шаблонов, а 'T' и' T const' - разные аргументы шаблона ... но это может показаться немного произвольным или круговым, поэтому OP задается вопросом, почему, например, эти два не являются специальными, чтобы создавать различные типы совместимых типов (castable). Это хороший пример только одной из причин, которая, когда человек начинает обдумывать, может быстро размножаться! - что cv-квалификация рассматривается здесь как дискриминатор типа. –

Смежные вопросы