Namespaces
Variants

std:: bind_front, std:: bind_back

From cppreference.net
Utilities library
Function objects
Partial function application
bind_front bind_back
(C++20) (C++23)
(C++11)
Function invocation
(C++17) (C++23)
Identity function object
(C++20)
Old binders and adaptors
( until C++17* )
( until C++17* )
( until C++17* )
( until C++17* )
( until C++17* ) ( until C++17* ) ( until C++17* ) ( until C++17* )
( until C++20* )
( until C++20* )
( until C++17* ) ( until C++17* )
( until C++17* ) ( until C++17* )

( until C++17* )
( until C++17* ) ( until C++17* ) ( until C++17* ) ( until C++17* )
( until C++20* )
( until C++20* )
Определено в заголовке <functional>
std::bind_front
template < class F, class ... Args >
constexpr /* unspecified */ bind_front ( F && f, Args && ... args ) ;
(1) (начиная с C++20)
template < auto ConstFn, class ... Args >
constexpr /* unspecified */ bind_front ( Args && ... args ) ;
(2) (начиная с C++26)
std::bind_back
template < class F, class ... Args >
constexpr /* unspecified */ bind_back ( F && f, Args && ... args ) ;
(3) (начиная с C++23)
template < auto ConstFn, class ... Args >
constexpr /* unspecified */ bind_back ( Args && ... args ) ;
(4) (начиная с C++26)

Шаблоны функций std::bind_front и std::bind_back создают обёртку вызова с совершенной пересылкой, которая позволяет вызывать целевой объект с его (1,2) первыми или (3,4) последними sizeof... ( Args ) параметрами, привязанными к args .

1,3) Обёртка вызова хранит копию целевого вызываемого объекта f .
2,4) Обёртка вызова не содержит вызываемую цель (это статически определено).
1) std :: bind_front ( f, bound_args... ) ( call_args... ) является эквивалентным выражением для
std:: invoke ( f, bound_args..., call_args... ) .
2) std :: bind_front < ConstFn > ( bound_args... ) ( call_args... ) является эквивалентным выражением для
std:: invoke ( ConstFn, bound_args..., call_args... ) .
3) std :: bind_back ( f, bound_args... ) ( call_args... ) является эквивалентным выражением для
std:: invoke ( f, call_args..., bound_args... ) .
4) std :: bind_back < ConstFn > ( bound_args... ) ( call_args... ) является эквивалентным выражением для
std:: invoke ( ConstFn, call_args..., bound_args... ) .

Следующие условия должны быть true , иначе программа является некорректной:

Содержание

Параметры

f - Callable объект (функциональный объект, указатель на функцию, ссылка на функцию, указатель на метод класса или указатель на член данных), который будет привязан к некоторым аргументам
args - список аргументов для привязки к ( 1,2 ) первым или ( 3,4 ) последним sizeof... ( Args ) параметрам вызываемой цели
Требования к типам
-
std:: decay_t < F > должен удовлетворять требованиям MoveConstructible .
-
std:: decay_t < Args > ... должны удовлетворять требованиям MoveConstructible .
-
decltype ( ConstFn ) должен удовлетворять требованиям Callable .

Возвращаемое значение

Функциональный объект (обёртка вызова) типа T , который не специфицирован, за исключением того, что типы объектов, возвращаемых двумя вызовами std::bind_front или std::bind_back с одинаковыми аргументами, совпадают.

Пусть bind-partial будет либо std::bind_front , либо std::bind_back .

Возвращаемый объект имеет следующие свойства:

bind-partial тип возвращаемого значения

Объекты-члены

Возвращаемый объект ведет себя так, как будто он содержит:

1,3) Член-объект fd типа std:: decay_t < F > прямое не-списковое инициализирование из std:: forward < F > ( f ) , и
1-4) Объект std::tuple tup , сконструированный с помощью std:: tuple < std:: decay_t < Args > ... > ( std:: forward < Args > ( args ) ... ) , за исключением того, что поведение присваивания возвращаемого объекта не определено, а имена приведены только для демонстрации.

Конструкторы

Возвращаемый тип bind-partial ведёт себя так, как если бы его конструкторы копирования/перемещения выполняли почленное копирование/перемещение. Он является CopyConstructible если все его объекты-члены (указанные выше) являются CopyConstructible , и является MoveConstructible в противном случае.

Функция-член operator()

Для объекта G , полученного из предыдущего вызова ( 1,3 ) bind-partial (f, args...) или ( 2,4 ) bind-partial <ConstFn>(args...) , когда glvalue g , обозначающий G , вызывается в выражении вызова функции g ( call_args... ) , происходит вызов сохраненного объекта, как если бы с помощью:

1) std:: invoke ( g. fd , std :: get < Ns > ( g. tup ) ..., call_args... ) , когда bind-partial является std::bind_front ,
2) std:: invoke ( ConstFn, std :: get < Ns > ( g. tup ) ..., call_args... ) , когда bind-partial является std::bind_front ,
3) std:: invoke ( g. fd , call_args..., std :: get < Ns > ( g. tup ) ... ) , когда bind-partial является std::bind_back ,
4) std:: invoke ( ConstFn, call_args..., std :: get < Ns > ( g. tup ) ... ) , когда bind-partial является std::bind_back ,

где

  • Ns является целочисленным набором 0, 1, ..., (sizeof...(Args) - 1) ,
  • g является lvalue в выражении std::invoke , если оно является lvalue в вызывающем выражении, и является rvalue в противном случае. Таким образом, std :: move ( g ) ( call_args... ) может перемещать связанные аргументы в вызов, тогда как g ( call_args... ) выполняло бы копирование.

Программа является некорректной, если g имеет тип с квалификатором volatile.

Член operator ( ) является noexcept если выражение std::invoke которое оно вызывает является noexcept (другими словами, он сохраняет спецификацию исключений базового оператора вызова).

Исключения

1,3) Выбрасывает любое исключение, выброшенное при вызове конструктора хранимого функционального объекта.
1-4) Выбрасывает любое исключение, выброшенное при вызове конструктора любого из связанных аргументов.

Примечания

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

Как описано в std::invoke , при вызове указателя на нестатическую функцию-член или указателя на нестатический член данных, первый аргумент должен быть ссылкой или указателем (включая, возможно, умные указатели, такие как std::shared_ptr и std::unique_ptr ) на объект, член которого будет доступен.

Аргументы для std::bind_front или std::bind_back копируются или перемещаются и никогда не передаются по ссылке, если не обернуты в std::ref или std::cref .

Обычно привязка аргументов к функции или функции-члену с использованием ( 1 ) std::bind_front и ( 3 ) std::bind_back требует хранения указателя на функцию вместе с аргументами, даже несмотря на то, что язык точно знает, какую функцию вызывать без необходимости разыменования указателя. Для гарантии "нулевой стоимости" в таких случаях C++26 вводит версии ( 2,4 ) (которые принимают вызываемый объект в качестве аргумента для постоянного шаблонного параметра ).

Макрос тестирования возможностей Значение Стандарт Функция
__cpp_lib_bind_front 201907L (C++20) std::bind_front , ( 1 )
202306L (C++26) Разрешение передачи вызываемых объектов как константных шаблонных аргументов в std::bind_front , ( 2 )
__cpp_lib_bind_back 202202L (C++23) std::bind_back , ( 3 )
202306L (C++26) Разрешение передачи вызываемых объектов как константных шаблонных аргументов в std::bind_back , ( 4 )

Возможная реализация

(2) bind_front
namespace detail
{
    template<class T, class U>
    struct copy_const
        : std::conditional<std::is_const_v<T>, U const, U> {};
    template<class T, class U,
             class X = typename copy_const<std::remove_reference_t<T>, U>::type>
    struct copy_value_category
        : std::conditional<std::is_lvalue_reference_v<T&&>, X&, X&&> {};
    template <class T, class U>
    struct type_forward_like
        : copy_value_category<T, std::remove_reference_t<U>> {};
    template <class T, class U>
    using type_forward_like_t = typename type_forward_like<T, U>::type;
}
template<auto ConstFn, class... Args>
constexpr auto bind_front(Args&&... args)
{
    using F = decltype(ConstFn);
    if constexpr (std::is_pointer_v<F> or std::is_member_pointer_v<F>)
        static_assert(ConstFn != nullptr);
    return
        [... bound_args(std::forward<Args>(args))]<class Self, class... T>
        (
            this Self&&, T&&... call_args
        )
        noexcept
        (
            std::is_nothrow_invocable_v<F,
                detail::type_forward_like_t<Self, std::decay_t<Args>>..., T...>
        )
        -> std::invoke_result_t<F,
                detail::type_forward_like_t<Self, std::decay_t<Args>>..., T...>
        {
            return std::invoke(ConstFn, std::forward_like<Self>(bound_args)...,
                               std::forward<T>(call_args)...);
        };
}
(4) bind_back
namespace detail { /* то же самое, что и выше */ }
template<auto ConstFn, class... Args>
constexpr auto bind_back(Args&&... args)
{
    using F = decltype(ConstFn);
    if constexpr (std::is_pointer_v<F> or std::is_member_pointer_v<F>)
        static_assert(ConstFn != nullptr);
    return
        [... bound_args(std::forward<Args>(args))]<class Self, class... T>
        (
            this Self&&, T&&... call_args
        )
        noexcept
        (
            std::is_nothrow_invocable_v<F,
                detail::type_forward_like_t<Self, T..., std::decay_t<Args>>...>
        )
        -> std::invoke_result_t<F,
                detail::type_forward_like_t<Self, T..., std::decay_t<Args>>...>
        {
            return std::invoke(ConstFn, std::forward<T>(call_args)...,
                               std::forward_like<Self>(bound_args)...);
        };
}

Пример

#include <cassert>
#include <functional>
int minus(int a, int b)
{
    return a - b;
}
struct S
{
    int val;
    int minus(int arg) const noexcept { return val - arg; }
};
int main()
{
    auto fifty_minus = std::bind_front(minus, 50);
    assert(fifty_minus(3) == 47); // эквивалентно: minus(50, 3) == 47
    auto member_minus = std::bind_front(&S::minus, S{50});
    assert(member_minus(3) == 47); //: S tmp{50}; tmp.minus(3) == 47
    // Спецификация noexcept сохраняется:
    static_assert(!noexcept(fifty_minus(3)));
    static_assert(noexcept(member_minus(3)));
    // Привязка лямбда-выражения:
    auto plus = [](int a, int b) { return a + b; };
    auto forty_plus = std::bind_front(plus, 40);
    assert(forty_plus(7) == 47); // эквивалентно: plus(40, 7) == 47
#if __cpp_lib_bind_front >= 202306L
    auto fifty_minus_cpp26 = std::bind_front<minus>(50);
    assert(fifty_minus_cpp26(3) == 47);
    auto member_minus_cpp26 = std::bind_front<&S::minus>(S{50});
    assert(member_minus_cpp26(3) == 47);
    auto forty_plus_cpp26 = std::bind_front<plus>(40);
    assert(forty_plus(7) == 47);
#endif
#if __cpp_lib_bind_back >= 202202L
    auto madd = [](int a, int b, int c) { return a * b + c; };
    auto mul_plus_seven = std::bind_back(madd, 7);
    assert(mul_plus_seven(4, 10) == 47); //: madd(4, 10, 7) == 47
#endif
#if __cpp_lib_bind_back >= 202306L
    auto mul_plus_seven_cpp26 = std::bind_back<madd>(7);
    assert(mul_plus_seven_cpp26(4, 10) == 47);
#endif
}

Ссылки

  • Стандарт C++26 (ISO/IEC 14882:2026):
  • TBD Шаблоны функций bind_front и bind_back [func.bind.partial]
  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 22.10.14 Функциональные шаблоны bind_front и bind_back [func.bind.partial]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 20.14.14 Шаблон функции bind_front [func.bind.front]

Смотрите также

(C++11)
связывает один или несколько аргументов с функциональным объектом
(шаблон функции)
(C++11)
создает функциональный объект из указателя на член
(шаблон функции)