Почему 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 превзошло бы цель (и может сломать сборку, если конструктор копирования будет удален). Именно по этой причине он использует ссылку (вместо значения) в этом возвращаемом типе.