Почему std:: make_tuple включает аргументы std:: reference_wrapper <X> в X &?
В стандарте С++ 11 указано, что (см. cppreference.com, см. также раздел 20.4.2.4 стандарта), в котором указано, что
template< class... Types >
tuple<VTypes...> make_tuple( Types&&... args );
Создает объект кортежа, выводя тип цели из типов аргументов.
Для каждого Ti
в Types...
соответствующий тип Vi
в Vtypes...
равен std::decay<Ti>::type
, если приложение std::decay
не приведет к std::reference_wrapper<X>
для некоторого типа X
, и в этом случае выведенное тип X&
.
Мне интересно: почему ссылочные обертки рассматриваются здесь специально?
Ответы
Ответ 1
Это более или менее основная цель reference_wrapper
.
Обычно std::make_tuple
всегда создает кортежи значений (std::decay
имитирует семантику передачи по значению). Учитывая, что int x, y; std::make_tuple(x, y);
делает std::tuple<int, int>
, хотя он будет выводить Types
как пакет ссылок int&, int&
. std::decay
преобразует их в int, int
.
reference_wrapper
позволяет принудительно создавать кортежи ссылок: std::make_tuple(std::ref(x), y)
сделает std::tuple<int&, int>
.
Другие части стандартной библиотеки используют reference_wrapper
таким же образом. Например, std::bind
обычно копирует/перемещает связанные аргументы в результирующий объект, но если вы хотите сохранить только ссылку, вы можете явно запросить его, передав reference_wrapper
.
Ответ 2
Ваше название вводит в заблуждение: с помощью std::reference_wrapper<X>
члены становятся X&
, а не X
. Причина этого преобразования заключается в том, что std::reference_wrapper<T>
является вспомогательным типом, предназначенным для превращения типа значения в ссылочный тип. Однако дополнительная конверсия, необходимая для того, чтобы она казалась таким образом, иногда мешает использованию. Таким образом, разворачивание ссылки там, где это возможно, представляется разумным: создание элемента std::tuple<...>
a T&
делает использование более естественным.
Ответ 3
Обычно люди используют std::reference_wrapper<X>
для хранения не скопируемых типов. Поэтому копирование их в make_tuple
превзошло бы цель (и может сломать сборку, если конструктор копирования будет удален). Именно по этой причине он использует ссылку (вместо значения) в этом возвращаемом типе.