Почему std::get не имеет единой подписи, которая принимает ссылку на пересылку

Почему std::get для std::tuple имеет так много перегрузок (http://en.cppreference.com/w/cpp/utility/tuple/get)? Один, соответствующий каждой возможной комбинации const & и &&? Для каждой комбинации квалификаторы const ref в возвращаемом значении одинаковы. Почему бы не использовать только одну перегрузку, которая принимает тип кортежа путем пересылки ссылки, а затем просто пересылает возвращаемое значение на основе сигнатуры ввода? Что-то вроде этого

template <int Index, typename TupleType>
decltype(auto) get(TupleType&& tup);

Подобные вещи облегчили бы людям понимание того, что делает функция get, и позволили бы избежать таких ошибок, как Проблема 2485 (https://wg21.cmeerw.net/lwg/issue2485)


person Curious    schedule 04.04.2017    source источник


Ответы (2)


std::get существовал до decltype(auto). Так что это было легко.

Хорошо, почему бы не изменить его?

Тело std::get не указано стандартом и не должно быть, поскольку разные компиляторы имеют разные макеты и реализации кортежей.

decltype(auto) не сообщает читателю стандарта, пользователю или разработчику компилятора, каков возвращаемый тип. Он просто говорит, что это выведено из тела. Что не указано в стандарте.

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

person Yakk - Adam Nevraumont    schedule 04.04.2017
comment
Следует отметить, что реализации могут свободно использовать decltype(auto) и только одну перегрузку. - person Nicol Bolas; 04.04.2017
comment
@Yakk означает ли это, что в подобном сценарии использование decltype(auto) является плохим дизайнерским решением, когда возвращаемое значение может быть либо rvalue, либо lvalue на основе выводов типа? Должен ли я иметь 4 перегрузки? - person Curious; 04.04.2017
comment
@любопытно, вы комитет по стандартам, документирующий интерфейсы, но не реализацию для миллионов программистов и авторов компиляторов? Если да, то это плохая идея. Если нет, то мой ответ не распространяется на ваш случай, и ваша ситуация недостаточно похожа. Если у вас есть совершенно другой вопрос, на который вам нужен ответ, проверьте, подходит ли он для публикации в stackoverflow, и если да, нажмите кнопку «Задать вопрос» и напишите его. Я не собираюсь перечислять плюсы и минусы в ветке комментариев. - person Yakk - Adam Nevraumont; 04.04.2017

Параметр std::get нельзя вывести, потому что std::get определен для многих разных типов. (Пример tuple, pair, array, variant).

По этой причине более чем любой другой std::get не может вывести свой тип параметра. Изменение его на дедукцию в этот момент нарушило бы реальный код, такой как типы, выведенные из кортежа. Например, предложенное изменение подписи даст подпись вида: template <class TupleLike, class = enable_if_t<IsStdTuple<TupleLike>::value>>> decltype(auto) get(TupleLike&&);

Эта сигнатура не допускает неявных преобразований в тип кортежа в интерфейсе, как это делали старые сигнатуры. Как уже упоминалось, это разбивает типы, производные от std::tuple, или типы, которые имеют оператор преобразования в std::tuple.

Libc++ реализует конструкторы преобразования tuple, pair и array с использованием одной универсальной перегрузки TupleLike. Как специалист по сопровождению, я хорошо знаком с этими проблемами реализации, и если бы я мог реализовать соответствующий std::get, как вы предлагаете, я бы уже это сделал.

person EricWF    schedule 04.04.2017
comment
Я не думаю, что типы с функцией преобразования в tuple все равно работают. Однако типы, производные от tuple, должны работать. - person T.C.; 04.04.2017
comment
Не могли бы вы использовать комбинацию параметров шаблона шаблона и std::is_convertible, чтобы проверить, можно ли преобразовать аргумент в кортеж или, в более общем случае, в параметр шаблона шаблона? - person Curious; 04.04.2017
comment
@Curious Вы не можете использовать is_convertible, потому что не знаете, какую специализацию tuple проверять. @T.C Типы с оператором преобразования в кортеж должны работать, но во внешних интерфейсах компилятора существует много расхождений в реализации. - person EricWF; 04.04.2017
comment
@EricWF Ты уверен? В прошлый раз, когда я проверял, вывод аргумента шаблона не просматривал пользовательские преобразования. - person T.C.; 06.04.2017