std:: bind
|
Definiert im Header
<functional>
|
||
|
template
<
class
F,
class
...
Args
>
/* unspecified */ bind ( F && f, Args && ... args ) ; |
(1) |
(seit C++11)
(constexpr seit C++20) |
|
template
<
class
R,
class
F,
class
...
Args
>
/* unspecified */ bind ( F && f, Args && ... args ) ; |
(2) |
(seit C++11)
(constexpr seit C++20) |
Die Funktionsvorlage
std::bind
erzeugt einen weiterleitenden Aufruf-Wrapper für
f
. Das Aufrufen dieses Wrappers ist gleichbedeutend mit dem Aufruf von
f
mit einigen seiner Argumente
gebunden
an
args
.
Wenn
std::
is_constructible
<
std::
decay
<
F
>
::
type
, F
>
::
value
gleich
false
ist, oder
std::
is_constructible
<
std::
decay
<
Arg_i
>
::
type
, Arg_i
>
::
value
gleich
false
für irgendeinen Typ
Arg_i
in
Args
ist, dann ist das Programm fehlerhaft.
Wenn
std::
decay
<
Ti
>
::
type
oder irgendein Typ in
Args
nicht
MoveConstructible
oder
Destructible
ist, ist das Verhalten undefiniert.
Inhaltsverzeichnis |
Parameter
| f | - | Callable Objekt (Funktionsobjekt, Zeiger auf Funktion, Referenz auf Funktion, Zeiger auf Memberfunktion oder Zeiger auf Datenelement), das an einige Argumente gebunden wird |
| args | - |
Liste der zu bindenden Argumente, wobei die ungebundenen Argumente durch die
Platzhalter
_1
,
_2
,
_3
... des Namespace
std::placeholders
ersetzt werden
|
Rückgabewert
Ein Funktionsobjekt
g
eines nicht näher spezifizierten Typs
T
, für das
std::
is_bind_expression
<
T
>
::
value
gleich
true
ist. Es besitzt die folgenden Member:
std::bind Rückgabetyp
Member-Objekte
Der Rückgabetyp von
std::bind
enthält ein Mitgliedsobjekt vom Typ
std::
decay
<
F
>
::
type
, konstruiert aus
std::
forward
<
F
>
(
f
)
, sowie ein Objekt für jedes der
args...
, vom Typ
std::
decay
<
Arg_i
>
::
type
, ähnlich konstruiert aus
std::
forward
<
Arg_i
>
(
arg_i
)
.
Konstruktoren
Der Rückgabetyp von
std::bind
ist
CopyConstructible
wenn alle seiner Member-Objekte (wie oben spezifiziert) CopyConstructible sind, andernfalls ist er
MoveConstructible
. Der Typ definiert die folgenden Member:
Member type
|
(bis C++20) |
Member-Funktion
operator()
Wenn g in einem Funktionsaufrufausdruck g ( u1, u2, ... uM ) aufgerufen wird, erfolgt ein Aufruf des gespeicherten Objekts, als ob durch
INVOKE
(
fd,
std::
forward
<
V1
>
(
v1
)
,
std::
forward
<
V2
>
(
v2
)
, ...,
std::
forward
<
VN
>
(
vN
)
)
, oder
INVOKE<R>
(
fd,
std::
forward
<
V1
>
(
v1
)
,
std::
forward
<
V2
>
(
v2
)
, ...,
std::
forward
<
VN
>
(
vN
)
)
,
wobei
fd
ein Wert vom Typ
std::
decay
<
F
>
::
type
ist, die Werte und Typen der gebundenen Argumente
v1
,
v2
, ...,
vN
wie
unten
spezifiziert bestimmt werden.
Wenn einige der Argumente, die im Aufruf von g ( ) bereitgestellt werden, nicht durch Platzhalter in g abgedeckt werden, werden die ungenutzten Argumente ausgewertet und verworfen.
Ein Aufruf von
operator
(
)
ist
nicht-werfend
oder ist ein
konstanter Teilausdruck
(seit C++20)
genau dann, wenn die zugrundeliegende
INVOKE
-Operation dies ist.
operator
(
)
nimmt an der Überladungsauflösung nur teil, wenn die
INVOKE
-Operation wohlgeformt ist, wenn sie als nicht-ausgewerteter Operand behandelt wird.
Wenn g mit volatile qualifiziert ist, ist das Programm fehlerhaft.
Wenn
INVOKE
(
fd, w1, w2, ..., wN
)
niemals ein gültiger Ausdruck für irgendwelche möglichen Werte
w1
,
w2
, ...,
wN
sein kann, ist das Verhalten undefiniert.
Gebundene Argumente
Für jedes gespeicherte Argument
arg_i
wird das entsprechende gebundene Argument
v_i
in der
INVOKE
- oder
INVOKE<R>
-Operation wie folgt bestimmt:
Fall 1: Referenz-Wrapper
Wenn
arg_i
vom Typ
std::
reference_wrapper
<
T
>
ist (zum Beispiel, wenn
std::ref
oder
std::cref
im ursprünglichen Aufruf von
std::bind
verwendet wurde), dann ist
v_i
gleich
arg_i.
get
(
)
und sein Typ
V_i
ist
T&
: Das gespeicherte Argument wird als Referenz an das aufgerufene Funktionsobjekt übergeben.
Fall 2: Bind-Ausdrücke
Wenn
arg_i
vom Typ
T
ist, für den
std::
is_bind_expression
<
T
>
::
value
gleich
true
ist (z.B. wenn ein anderer
std::bind
-Ausdruck direkt in den ursprünglichen Aufruf von
std::bind
übergeben wurde), dann führt
std::bind
Funktionskomposition durch: Anstatt das Funktionsobjekt zu übergeben, das der Bind-Subausdruck zurückgeben würde, wird der Subausdruck sofort ausgewertet und sein Rückgabewert an das äußere aufrufbare Objekt übergeben. Wenn der Bind-Subausdruck Platzhalterargumente enthält, werden diese mit dem äußeren Bind geteilt (ausgewählt aus
u1
,
u2
, ...
). Konkret ist
v_i
gleich
arg_i
(
std::
forward
<
Uj
>
(
uj
)
...
)
und sein Typ
V_i
ist
std::
result_of
<
T
cv
&
(
Uj
&&
...
)
>
::
type
&&
(bis C++17)
std::
invoke_result_t
<
T
cv
&
, Uj
&&
...
>
&&
(seit C++17)
(CV-Qualifikation ist identisch mit der von
g
).
Fall 3: placeholders
Wenn
arg_i
vom Typ
T
ist, für den
std::
is_placeholder
<
T
>
::
value
nicht
0
ist (d.h. ein Platzhalter wie
std::placeholders::_1, _2, _3, ...
wurde als Argument im ursprünglichen Aufruf von
std::bind
verwendet), dann wird das durch den Platzhalter angegebene Argument (
u1
für
_1
,
u2
für
_2
, usw.) an das aufrufbare Objekt übergeben:
v_i
ist
std::
forward
<
Uj
>
(
uj
)
und sein Typ
V_i
ist
Uj&&
.
Fall 4: gewöhnliche Argumente
Andernfalls wird
arg_i
als Lvalue-Argument an das aufrufbare Objekt übergeben:
v_i
ist einfach
arg_i
und sein Typ
V_i
ist
T
cv
&
, wobei
cv
die gleiche CV-Qualifikation wie die von
g
ist.
Exceptions
Wirft nur, wenn die Konstruktion von
std::
decay
<
F
>
::
type
aus
std::
forward
<
F
>
(
f
)
wirft, oder einer der Konstruktoren für
std::
decay
<
Arg_i
>
::
type
aus dem entsprechenden
std::
forward
<
Arg_i
>
(
arg_i
)
wirft, wobei
Arg_i
der i-te Typ und
arg_i
das i-te Argument in
Args... args
ist.
Hinweise
Wie in Callable beschrieben, muss beim Aufruf eines Zeigers auf eine nicht-statische Member-Funktion oder eines Zeigers auf ein nicht-statisches Datenelement 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 Member zugegriffen wird.
Die Argumente für bind werden kopiert oder verschoben und niemals als Referenz übergeben, es sei denn, sie sind in std::ref oder std::cref eingeschlossen.
Doppelte Platzhalter im selben Bind-Ausdruck (mehrere _1 zum Beispiel) sind erlaubt, aber die Ergebnisse sind nur wohldefiniert, wenn das entsprechende Argument ( u1 ) ein Lvalue oder ein nicht bewegbarer Rvalue ist.
Beispiel
#include <functional> #include <iostream> #include <memory> #include <random> void f(int n1, int n2, int n3, const int& n4, int n5) { std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n'; } int g(int n1) { return n1; } struct Foo { void print_sum(int n1, int n2) { std::cout << n1 + n2 << '\n'; } int data = 10; }; int main() { using namespace std::placeholders; // für _1, _2, _3... std::cout << "1) Argument-Reihenfolgeänderung und Pass-by-Reference: "; int n = 7; // (_1 und _2 stammen aus std::placeholders und repräsentieren zukünftige // Argumente, die an f1 übergeben werden) auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n); n = 10; f1(1, 2, 1001); // 1 wird durch _1 gebunden, 2 wird durch _2 gebunden, 1001 wird nicht verwendet // führt einen Aufruf von f(2, 42, 1, n, 7) aus std::cout << "2) Erzielen des gleichen Effekts mit einem Lambda: "; n = 7; auto lambda = [&ncref = n, n](auto a, auto b, auto /*unused*/) { f(b, 42, a, ncref, n); }; n = 10; lambda(1, 2, 1001); // dasselbe wie ein Aufruf von f1(1, 2, 1001) std::cout << "3) verschachtelte Bind-Subausdrücke teilen sich die Platzhalter: "; auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5); f2(10, 11, 12); // führt einen Aufruf von f(12, g(12), 12, 4, 5) aus; std::cout << "4) binden Sie einen Zufallszahlengenerator mit einer Verteilung: "; std::default_random_engine e; std::uniform_int_distribution<> d(0, 10); auto rnd = std::bind(d, e); // eine Kopie von e wird in rnd gespeichert for (int n = 0; n < 10; ++n) std::cout << rnd() << ' '; std::cout << '\n'; std::cout << "5) an einen Zeiger auf eine Member-Funktion binden: "; Foo foo; auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1); f3(5); std::cout << "6) Bindung an ein mem_fn, das ein Zeiger auf eine Member-Funktion ist: "; auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum); auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1); f4(5); std::cout << "7) Bindung an einen Zeiger auf ein Datenmitglied: "; auto f5 = std::bind(&Foo::data, _1); std::cout << f5(foo) << '\n'; std::cout << "8) an ein mem_fn binden, das ein Zeiger auf ein Datenmitglied ist: "; auto ptr_to_data = std::mem_fn(&Foo::data); auto f6 = std::bind(ptr_to_data, _1); std::cout << f6(foo) << '\n'; std::cout << "9) Verwenden Sie Smart Pointer, um Member der referenzierten Objekte aufzurufen: "; std::cout << f6(std::make_shared<Foo>(foo)) << ' ' << f6(std::make_unique<Foo>(foo)) << '\n'; }
Ausgabe:
1) Argumenten-Umordnung und Pass-by-Reference: 2 42 1 10 7 2) Erzielen des gleichen Effekts mit einem Lambda: 2 42 1 10 7 3) Verschachtelte Bind-Subausdrücke teilen sich die Platzhalter: 12 12 12 4 5 4) Binden eines RNG mit einer Verteilung: 0 1 8 5 5 2 0 7 7 10 5) Binden an einen Zeiger auf eine Member-Funktion: 100 6) Binden an ein mem_fn, das ein Zeiger auf eine Member-Funktion ist: 100 7) Binden an einen Zeiger auf ein Datenmitglied: 10 8) Binden an ein mem_fn, das ein Zeiger auf ein Datenmitglied ist: 10 9) Verwenden von Smart Pointern zum Aufruf von Membern der referenzierten Objekte: 10 10
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| LWG 2021 | C++11 |
1. die gebundenen Argumente
wurden nicht an fd weitergeleitet 2. in Fall 2 war der Typ von
V_i
std:: result_of < T cv ( Uj... ) > :: type |
1. weitergeleitet
2. geändert zu std:: result_of < T cv & ( Uj && ... ) > :: type && |
Siehe auch
|
(C++20)
(C++23)
|
bindet eine variable Anzahl von Argumenten in einer bestimmten Reihenfolge an ein Funktionsobjekt
(Funktions-Template) |
|
(C++11)
|
Platzhalter für die ungebundenen Argumente in einem
std::bind
-Ausdruck
(Konstante) |
|
(C++11)
|
erstellt ein Funktionsobjekt aus einem Zeiger auf ein Element
(Funktions-Template) |