std:: bind_front, std:: bind_back
|
Definiert im Header
<functional>
|
||
std::bind_front
|
||
|
template
<
class
F,
class
...
Args
>
constexpr /* unspecified */ bind_front ( F && f, Args && ... args ) ; |
(1) | (seit C++20) |
|
template
<
auto
ConstFn,
class
...
Args
>
constexpr /* unspecified */ bind_front ( Args && ... args ) ; |
(2) | (seit C++26) |
std::bind_back
|
||
|
template
<
class
F,
class
...
Args
>
constexpr /* unspecified */ bind_back ( F && f, Args && ... args ) ; |
(3) | (seit C++23) |
|
template
<
auto
ConstFn,
class
...
Args
>
constexpr /* unspecified */ bind_back ( Args && ... args ) ; |
(4) | (seit C++26) |
Funktionsvorlagen
std::bind_front
und
std::bind_back
erzeugen einen perfekten Weiterleitungs-Aufrufwrapper, der es ermöglicht, das aufrufbare Ziel mit seinen
(1,2)
ersten oder
(3,4)
letzten
sizeof...
(
Args
)
Parametern an
args
gebunden aufzurufen.
Die folgenden Bedingungen müssen true sein, andernfalls ist das Programm fehlerhaft:
- (1,3) std:: is_constructible_v < std:: decay_t < F > , F > ,
- (1,3) std:: is_move_constructible_v < std:: decay_t < F >> ,
-
(2,4)
Falls
decltype
(
ConstFn
)
ein Zeiger oder ein Zeiger-auf-Mitglied ist, dann ist
ConstFnkein Nullzeiger, - ( std:: is_constructible_v < std:: decay_t < Args > , Args > && ... ) ,
- ( std:: is_move_constructible_v < std:: decay_t < Args >> && ... ) .
Inhaltsverzeichnis |
Parameter
| f | - | Callable Objekt (Funktionsobjekt, Funktionszeiger, Funktionsreferenz, Zeiger auf Elementfunktion oder Zeiger auf Datenelement), das an einige Argumente gebunden wird |
| args | - | Liste der Argumente, die an die ( 1,2 ) ersten oder ( 3,4 ) letzten sizeof... ( Args ) Parameter des aufrufbaren Ziels gebunden werden |
| Typanforderungen | ||
-
std::
decay_t
<
F
>
muss die Anforderungen von
MoveConstructible
erfüllen.
|
||
-
std::
decay_t
<
Args
>
...
muss die Anforderungen von
MoveConstructible
erfüllen.
|
||
-
decltype
(
ConstFn
)
muss die Anforderungen von
Callable
erfüllen.
|
||
Rückgabewert
Ein Funktionsobjekt (der Aufruf-Wrapper) vom Typ
T
, der nicht näher spezifiziert ist, außer dass die Typen der Objekte, die von zwei Aufrufen von
std::bind_front
oder
std::bind_back
mit denselben Argumenten zurückgegeben werden, gleich sind.
Lassen Sie
bind-partial
entweder
std::bind_front
oder
std::bind_back
sein.
Das zurückgegebene Objekt hat folgende Eigenschaften:
bind-partial Rückgabetyp
Member-Objekte
Das zurückgegebene Objekt verhält sich so, als ob es Folgendes enthält:
fd
vom Typ
std::
decay_t
<
F
>
direkt-nicht-Listen-initialisiert von
std::
forward
<
F
>
(
f
)
, und
tup
konstruiert mit
std::
tuple
<
std::
decay_t
<
Args
>
...
>
(
std::
forward
<
Args
>
(
args
)
...
)
, mit der Ausnahme, dass das Zuweisungsverhalten des zurückgegebenen Objekts nicht spezifiziert ist und die Namen nur zur Veranschaulichung dienen.
Konstruktoren
Der Rückgabetyp von
bind-partial
verhält sich so, als ob seine Kopier-/Verschiebekonstruktoren eine elementweise Kopie/Verschiebung durchführen. Er ist
CopyConstructible
wenn alle seine Mitgliedsobjekte (wie oben spezifiziert)
CopyConstructible
sind, andernfalls ist er
MoveConstructible
.
Member-Funktion
operator()
Gegeben ein Objekt
G
erhalten von einem früheren Aufruf von
(
1,3
)
bind-partial
(f, args...)
oder
(
2,4
)
bind-partial
<ConstFn>(args...)
, wenn ein Glvalue
g
das
G
bezeichnet in einem Funktionsaufrufausdruck
g
(
call_args...
)
aufgerufen wird, findet eine Aufruf des gespeicherten Objekts statt, als ob durch:
bind-partial
std::bind_front
ist,
bind-partial
std::bind_front
ist,
bind-partial
std::bind_back
ist,
bind-partial
gleich
std::bind_back
ist,
wo
-
-
Nsist eine Integer-Pack0, 1, ..., (sizeof...(Args) - 1), -
gist ein Lvalue im std::invoke -Ausdruck, wenn es ein Lvalue im Aufrufausdruck ist, andernfalls ist es ein Rvalue. Daher kann std :: move ( g ) ( call_args... ) die gebundenen Argumente in den Aufruf verschieben, während g ( call_args... ) kopieren würde.
-
Das Programm ist fehlerhaft, wenn
g
einen volatile-qualifizierten Typ hat.
Der Member operator ( ) ist noexcept wenn der std::invoke Ausdruck, den er aufruft, noexcept ist (mit anderen Worten, er bewahrt die Ausnahmespezifikation des zugrundeliegenden Aufrufoperators).
Ausnahmen
Hinweise
Diese Funktionsvorlagen sollen
std::bind
ersetzen. Im Gegensatz zu
std::bind
unterstützen sie keine beliebige Neuordnung von Argumenten und haben keine spezielle Behandlung für verschachtelte Bind-Ausdrücke oder
std::reference_wrapper
s. Andererseits berücksichtigen sie die Wertkategorie des Aufrufwrapper-Objekts und propagieren die Ausnahmespezifikation des zugrundeliegenden Aufrufoperators.
Wie in std::invoke beschrieben, muss beim Aufruf eines Zeigers auf eine nicht-statische Member-Funktion oder eines Zeigers auf ein nicht-statisches Datenmitglied das erste Argument eine Referenz oder ein Zeiger (einschließlich möglicherweise intelligenter Zeiger wie std::shared_ptr und std::unique_ptr ) auf ein Objekt sein, auf dessen Mitglied zugegriffen wird.
Die Argumente für
std::bind_front
oder
std::bind_back
werden kopiert oder verschoben und niemals als Referenz übergeben, es sei denn, sie sind in
std::ref
oder
std::cref
eingewickelt.
Typischerweise erfordert das Binden von Argumenten an eine Funktion oder eine Memberfunktion mit
(
1
)
std::bind_front
und
(
3
)
std::bind_back
das Speichern eines Funktionszeigers zusammen mit den Argumenten, obwohl die Sprache genau weiß, welche Funktion aufgerufen werden soll, ohne dass der Zeiger dereferenziert werden muss. Um in diesen Fällen "Zero Cost" zu garantieren, führt C++26 die Versionen
(
2,4
)
ein (die das aufrufbare Objekt als Argument für
constant template parameter
akzeptieren).
| Feature-Test Makro | Wert | Std | Funktion |
|---|---|---|---|
__cpp_lib_bind_front
|
201907L
|
(C++20) |
std::bind_front
,
(
1
)
|
202306L
|
(C++26) |
Erlaubt das Übergeben von aufrufbaren Objekten als konstante Template-Argumente an
std::bind_front
,
(
2
)
|
|
__cpp_lib_bind_back
|
202202L
|
(C++23) |
std::bind_back
,
(
3
)
|
202306L
|
(C++26) |
Erlaubt das Übergeben von aufrufbaren Objekten als konstante Template-Argumente an
std::bind_back
,
(
4
)
|
Mögliche Implementierung
| (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> oder 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 { /* ist gleich wie oben */ } template<auto ConstFn, class... Args> constexpr auto bind_back(Args&&... args) { using F = decltype(ConstFn); if constexpr (std::is_pointer_v<F> oder 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)...); }; } |
Beispiel
#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); // entspricht: 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-Spezifikation bleibt erhalten: static_assert(!noexcept(fifty_minus(3))); static_assert(noexcept(member_minus(3))); // Bindung einer Lambda-Funktion: auto plus = [](int a, int b) { return a + b; }; auto forty_plus = std::bind_front(plus, 40); assert(forty_plus(7) == 47); // entspricht: 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 }
Referenzen
- C++26-Standard (ISO/IEC 14882:2026):
-
- TBD Funktionsvorlagen bind_front und bind_back [func.bind.partial]
- C++23-Standard (ISO/IEC 14882:2024):
-
- 22.10.14 Funktionsvorlagen bind_front und bind_back [func.bind.partial]
- C++20-Standard (ISO/IEC 14882:2020):
-
- 20.14.14 Funktionsvorlage bind_front [func.bind.front]
Siehe auch
|
(C++11)
|
bindet ein oder mehrere Argumente an ein Funktionsobjekt
(Funktions-Template) |
|
(C++11)
|
erstellt ein Funktionsobjekt aus einem Zeiger auf ein Mitglied
(Funktions-Template) |