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 /* 未指定 */ bind_front ( F && f, Args && ... args ) ;
(1) (C++20 起)
template < auto ConstFn, class ... Args >
constexpr /* 未指定 */ bind_front ( Args && ... args ) ;
(2) (C++26 起)
std::bind_back
template < class F, class ... Args >
constexpr /* 未指定 */ bind_back ( F && f, Args && ... args ) ;
(3) (C++23 起)
template < auto ConstFn, class ... Args >
constexpr /* 未指定 */ 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 - 将被绑定到某些参数的 可调用 对象(函数对象、函数指针、函数引用、成员函数指针或数据成员指针)
args - 要绑定到可调用目标 ( 1,2 ) 前或 ( 3,4 ) sizeof... ( Args ) 个参数的参数列表
类型要求
-
std:: decay_t < F > 必须满足 可移动构造 要求。
-
std:: decay_t < Args > ... 必须满足 可移动构造 要求。
-
decltype ( ConstFn ) 必须满足 可调用 要求。

返回值

一个类型为 T 的函数对象(调用包装器),其具体类型未指定,但通过相同参数两次调用 std::bind_front std::bind_back 所返回对象的类型保持一致。

bind-partial std::bind_front std::bind_back

返回的对象具有以下属性:

bind-partial 返回类型

成员对象

返回的对象行为如同持有:

1,3) 类型为 std:: decay_t < F > 的成员对象 fd ,直接非列表初始化自 std:: forward < F > ( f ) ,以及
1-4) 使用 std:: tuple < std:: decay_t < Args > ... > ( std:: forward < Args > ( args ) ... ) 构造的 std::tuple 对象 tup ,但返回对象的赋值行为未指定且名称仅用于说明目的。

构造函数

bind-partial 的返回类型行为如同其拷贝/移动构造函数执行成员级的拷贝/移动。若其所有成员对象(如上所述)均为 可拷贝构造 ,则其为 可拷贝构造 ;否则为 可移动构造

成员函数 operator()

给定从先前调用 ( 1,3 ) bind-partial (f, args...) ( 2,4 ) bind-partial <ConstFn>(args...) 获得的对象 G ,当指代 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 在调用表达式中为左值,则在 std::invoke 表达式中为左值;否则为右值。因此 std :: move ( g ) ( call_args... ) 可将绑定参数移动至调用中,而 g ( call_args... ) 会进行拷贝。

g 具有 volatile 限定类型,则程序非良构。

成员函数 operator ( ) noexcept ,当且仅当其调用的 std::invoke 表达式为 noexcept(即保留底层调用操作符的异常规范)。

异常

1,3) 抛出通过调用存储函数对象的构造函数所抛出的任何异常。
1-4) 抛出通过调用任何绑定参数的构造函数所抛出的异常。

注释

这些函数模板旨在替代 std::bind 。与 std::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)));
    // 绑定 lambda 表达式:
    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):
  • 待定 函数模板 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)
从成员指针创建函数对象
(函数模板)