std:: bind_front, std:: bind_back
|
ν€λ νμΌμ μ μλ¨
<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
λ νΈμΆ κ°λ₯ λμ(callable target)μ
(1,2)
첫 λ²μ§Έ λλ
(3,4)
λ§μ§λ§
sizeof...
(
Args
)
κ°μ λ§€κ°λ³μλ₯Ό
args
μ λ°μΈλ©νμ¬ μλ²½ν μ λ¬(perfect forwarding) νΈμΆ λνΌλ₯Ό μμ±ν©λλ€.
λ€μ 쑰건λ€μ΄ 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 | - | 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 λ°ν νμ
λ©€λ² κ°μ²΄
λ°νλ κ°μ²΄λ λ€μκ³Ό κ°μ΄ 보μ νλ κ²μ²λΌ λμν©λλ€:
fd
κ° νμ
std::
decay_t
<
F
>
λ‘λΆν°
std::
forward
<
F
>
(
f
)
λ₯Ό μ¬μ©νμ¬ μ§μ -λΉλͺ©λ‘-μ΄κΈ°νλκ³ , 그리κ³
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...
)
μμ νΈμΆλλ©΄, μ μ₯λ κ°μ²΄μ νΈμΆμ΄ λ€μκ³Ό κ°μ΄ μνλ©λλ€:
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λ νΈμΆ ννμμμ lvalueμΈ κ²½μ° std::invoke ννμμμ lvalueμ΄λ©°, κ·Έλ μ§ μμ κ²½μ° rvalueμ λλ€. λ°λΌμ std :: move ( g ) ( call_args... ) λ λ°μΈλ©λ μΈμλ€μ νΈμΆλ‘ μ΄λμν¬ μ μμ§λ§, g ( call_args... ) λ 볡μ¬ν©λλ€.
-
νλ‘κ·Έλ¨μ
g
κ° volatile νμ νμ
μ κ°μ§ κ²½μ° νμμ΄ μλͺ»λμμ΅λλ€.
λ©€λ² operator ( ) λ noexcept μ λλ€. λ§μ½ std::invoke ννμμ΄ noexceptμΈ κ²½μ° (λ€μ λ§ν΄, κΈ°λ³Έ νΈμΆ μ°μ°μμ μμΈ λͺ μΈλ₯Ό 보쑴ν©λλ€).
μμΈ
μ°Έκ³ μ¬ν
μ΄ ν¨μ ν
νλ¦Ώλ€μ
std::bind
λ₯Ό λ체νκΈ° μν΄ κ³ μλμμ΅λλ€.
std::bind
μ λ¬λ¦¬, μ΄λ€μ μμμ μΈμ μ¬λ°°μ΄μ μ§μνμ§ μμΌλ©° μ€μ²©λ bind-expressionμ΄λ
std::reference_wrapper
μ λν νΉλ³ν μ²λ¦¬λ₯Ό μ 곡νμ§ μμ΅λλ€. λ°λ©΄μ, μ΄λ€μ νΈμΆ λνΌ κ°μ²΄μ κ° λ²μ£Ό(value category)λ₯Ό κ³ λ €νλ©° κΈ°λ³Έ νΈμΆ μ°μ°μμ μμΈ λͺ
μΈ(exception specification)λ₯Ό μ νν©λλ€.
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)
|
νλ μ΄μμ μΈμλ₯Ό ν¨μ κ°μ²΄μ λ°μΈλ©ν©λλ€
(function template) |
|
(C++11)
|
λ©€λ² ν¬μΈν°λ‘λΆν° ν¨μ κ°μ²΄λ₯Ό μμ±ν©λλ€
(function template) |