std:: bind_front, std:: bind_back
|
定义于头文件
<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
来调用可调用目标。
以下条件必须为 true ,否则程序将是非良构的:
- (1,3) std:: is_constructible_v < std:: decay_t < F > , F > ,
- (1,3) std:: is_move_constructible_v < std:: decay_t < F >> ,
-
(2,4)
若
decltype
(
ConstFn
)
为指针或成员指针类型,则
ConstFn必须为非空指针, - ( std:: is_constructible_v < std:: decay_t < Args > , Args > && ... ) ,
- ( std:: is_move_constructible_v < std:: decay_t < Args >> && ... ) .
目录 |
参数
| 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 返回类型
成员对象
返回的对象行为如同持有:
tup
,但返回对象的赋值行为未指定且名称仅用于说明目的。
构造函数
bind-partial
的返回类型行为如同其拷贝/移动构造函数执行成员级的拷贝/移动。若其所有成员对象(如上所述)均为
可拷贝构造
,则其为
可拷贝构造
;否则为
可移动构造
。
成员函数
operator()
给定从先前调用
(
1,3
)
bind-partial
(f, args...)
或
(
2,4
)
bind-partial
<ConstFn>(args...)
获得的对象
G
,当指代
G
的泛左值
g
在函数调用表达式
g
(
call_args...
)
中被调用时,会触发存储对象的调用,如同通过:
bind-partial
为
std::bind_front
时,
bind-partial
为
std::bind_front
时,
bind-partial
为
std::bind_back
时,
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(即保留底层调用操作符的异常规范)。
异常
注释
这些函数模板旨在替代
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)
|
从成员指针创建函数对象
(函数模板) |