Как работает эта постоянная ссылка для std:: pair?

#c #stl #constants #std-pair

#c #stl #константы #std-pair

Вопрос:

Рассмотрим std::map класс в STL:

 template < class Key,                                     // map::key_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;
  

Итераторы для std::map возврата объектов типа

 std::pair<const key_type, T>
  

Здесь важно отметить, что первым членом пары является const . Это означает, что следующее назначение ссылки недопустимо.

 std::pair<key_type, T>amp; reference = *map_iterator;        // Incorrect, key_type is not const

std::pair<const key_type, T>amp; reference = *map_iterator;  // Correct
  

Однако, следующее выражение является допустимым :

 const std::pair<key_type, T>amp; reference = *map_iterator;  // Correct, const reference is okay
  

Итак, с помощью некоторого механизма на объекты типа std::pair<const key_type, T> можно ссылаться по ссылке типа const std::pair<key_type, T> . Это логически желательно (поскольку const наличие std::pair подразумевается const наличие обоих членов first и second , что совместимо с std::pair<const key_type, T> ).

Однако мне интересно узнать, какой механизм реализации C делает такую совместимость возможной. Я уверен, что существуют способы реализации std:: pair, где два приведенных выше ссылочных типа были бы несовместимы.

Ответ №1:

Когда вы делаете

 const std::pair<key_type, T>amp; reference = *map_iterator;
  

*map_iterator возвращает std::pair<const key_type, T>amp; . Затем вы копируете инициализируете std::pair<key_type, T> из этого, а затем привязываете reference к этой временной переменной. Поскольку у вас есть ссылка на const , это продлит срок службы этого временного элемента до срока службы ссылки, и теперь у вас есть элемент, который является копией элемента из map. В основном вы сделали

 std::pair<key_type, T> copy = *map_iterator; 
  

Приведенная выше последовательность преобразований работает, потому что вам разрешено до одного пользовательского преобразования при инициализации, и компилятор попытается сделать это, чтобы предоставить вам действительную инициализацию.

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

1. Спасибо! Можете ли вы предоставить какую-либо ссылку для утверждения «вам разрешено до одного пользовательского преобразования при инициализации»?

2. @johngreen Конечно. Проверьте: en.cppreference.com/w/cpp/language/implicit_conversion