Зачем использовать std :: bind_front вместо лямбда-выражений в C ++ 20? - PullRequest
41 голосов
/ 09 июля 2020

Как упоминалось в аналогичном вопросе ( Зачем использовать привязку вместо лямбда-выражений в С ++ 14? ) Ответ был - нет причин (и также упоминалось, почему было бы лучше использовать лямбды).

Мой вопрос: если в C ++ 14 больше не было причин использовать bind, почему комитет по стандартам счел необходимым добавить std::bind_front в C ++ 20?

Есть ли у него какое-то новое преимущество перед лямбдой?

Ответы [ 2 ]

47 голосов
/ 09 июля 2020

bind_front связывает первые параметры X, но если вызываемый объект требует дополнительных параметров, они прикрепляются к концу. Это делает bind_front очень удобочитаемым, когда вы привязываете только несколько первых параметров функции.

Очевидным примером может быть создание вызываемого объекта для функции-члена, привязанной к конкретному экземпляру c:

type *instance = ...;

//lambda
auto func = [instance](auto &&... args) -> decltype(auto) {return instance->function(std::forward<decltype(args)>(args)...);}

//bind
auto func = std::bind_front(&type::function, instance);

Версия bind_front - много менее шумная. Он переходит прямо к делу, имея ровно 3 именованных объекта: bind_front, вызываемую функцию-член и экземпляр, для которого она будет вызываться. И это все, что требуется в нашей ситуации: маркер для обозначения того, что мы создаем привязку первых параметров функции, функции, которую нужно связать, и параметра, который мы хотим привязать. Нет никакого постороннего синтаксиса или других деталей.

Напротив, лямбда содержит много вещей, которые нас просто не волнуют в этом месте. Бит auto... args, материал std::forward и т. Д. c. Немного сложнее понять, что он делает, и определенно намного дольше читать.

Обратите внимание, что bind_front вообще не позволяет использовать заполнители bind, поэтому на самом деле это не замена. Это скорее сокращение для наиболее полезных форм bind.

32 голосов
/ 09 июля 2020

В документе, в котором это предложено Упрощенное приложение частичной функции , есть несколько хороших убедительных примеров использования. Я резюмирую их здесь, потому что в противном случае мне пришлось бы процитировать большую часть статьи, поэтому обязательно go проверьте это:

Automati c perfect forwarding

Использование лямбда-выражения потребует std::forward шаблон

Распространение изменчивости

В случае сохранения объекта по значению std::bind и std::bind_front распространяют константность, но в случае захвата лямбды пользователь должен выбрать изменяемый или константный проблемы с созданием версии

Сохранение типа возвращаемого значения

Использование лямбда-выражения потребует -> decltype(auto) шаблона на стороне пользователя.

Сохранение категории значений

Как сохранение изменчивости , за исключением того, что сейчас мы говорим о lvalue / rvalue, и только std::bind_front делает это правильно

Поддержка одноразового вызова

Следствие распространения изменчивости и сохранения категории значений

Сохранение спецификации исключения

Это особенно важно сейчас, поскольку спецификация исключения теперь является частью системы типов. м

cppreference также содержит несколько полезных замечаний:

Эта функция предназначена для замены std :: bind. В отличие от std :: bind, он не поддерживает произвольную перестановку аргументов и не имеет специальной обработки для вложенных bind-выражений или std :: reference_wrappers. С другой стороны, он обращает внимание на категорию значения объекта-оболочки вызова и распространяет спецификацию исключения для основного оператора вызова.

...