Namensräume
Varianten
Aktionen

std::bind_front, std::bind_back

Von cppreference.com
< cpp‎ | utility‎ | functional
 
 
Dienstprogramm-Bibliotheken
Sprachunterstützung
Typunterstützung (Basistypen, RTTI)
Bibliotheks-Feature-Test-Makros (C++20)
Programm-Dienstprogramme
Variadische Funktionen
Coroutine-Unterstützung (C++20)
Vertragsunterstützung (C++26)
Drei-Wege-Vergleich
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

Allgemeine Hilfsmittel
Relationale Operatoren (in C++20 veraltet)
 
Funktionsobjekte
Partielle Funktionsanwendung
bind_frontbind_back
(C++20)(C++23)
(C++11)
Funktionsaufruf
(C++17)(C++23)
Identitätsfunktions-Objekt
(C++20)
Transparente Operator-Wrapper
(C++14)
(C++14)
(C++14)
(C++14)  
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)

Alte Binder und Adaptoren
(bis C++17*)
(bis C++17*)
(bis C++17*)
(bis C++17*)
(bis C++17*)(bis C++17*)(bis C++17*)(bis C++17*)
(bis C++20*)
(bis C++20*)
(bis C++17*)(bis C++17*)
(bis C++17*)(bis C++17*)

(bis C++17*)
(bis C++17*)(bis C++17*)(bis C++17*)(bis C++17*)
(bis C++20*)
(bis C++20*)
 
Definiert in der Header-Datei <functional>
std::bind_front
template< class F, class... Args >
constexpr /* nicht spezifiziert */ bind_front( F&& f, Args&&... args );
(1) (seit C++20)
template< auto ConstFn, class... Args >
constexpr /* nicht spezifiziert */ bind_front( Args&&... args );
(2) (seit C++26)
std::bind_back
template< class F, class... Args >
constexpr /* nicht spezifiziert */ bind_back( F&& f, Args&&... args );
(3) (seit C++23)
template< auto ConstFn, class... Args >
constexpr /* nicht spezifiziert */ bind_back( Args&&... args );
(4) (seit C++26)

Die Funktions-Templates std::bind_front und std::bind_back generieren einen "perfect forwarding call wrapper", der es erlaubt, das aufrufbare Ziel mit seinen (1,2) vorderen oder (3,4) hinteren sizeof...(Args) Parametern, die an args gebunden sind, aufzurufen.

1,3) Der Call Wrapper speichert eine Kopie des aufrufbaren Zielobjekts f.
2,4) Der Call Wrapper speichert kein aufrufbares Ziel (dieses ist statisch bestimmt).
1) std::bind_front(f, bound_args...)(call_args...) ist ausdrucksäquivalent zu
std::invoke(f, bound_args..., call_args...).
2) std::bind_front<ConstFn>(bound_args...)(call_args...) ist ausdrucksäquivalent zu
std::invoke(ConstFn, bound_args..., call_args...).
3) std::bind_back(f, bound_args...)(call_args...) ist ausdrucksäquivalent zu
std::invoke(f, call_args..., bound_args...).
4) std::bind_back<ConstFn>(bound_args...)(call_args...) ist ausdrucksäquivalent zu
std::invoke(ConstFn, call_args..., bound_args...).

Die folgenden Bedingungen müssen true sein, andernfalls ist das Programm ill-formed

Inhalt

[edit] Parameter

f - Callable-Objekt (Funktionsobjekt, Zeiger auf Funktion, Referenz auf Funktion, Zeiger auf Member-Funktion oder Zeiger auf Datenmitglied), das an einige Argumente gebunden werden soll
args - Liste der Argumente, die an die (1,2) vorderen oder (3,4) hinteren sizeof...(Args) Parameter des aufrufbaren Ziels gebunden werden sollen
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.

[edit] Rückgabewert

Ein Funktionsobjekt (der Call Wrapper) vom Typ T, das nicht spezifiziert ist, außer dass die Typen der von zwei Aufrufen von std::bind_front oder std::bind_back mit denselben Argumenten zurückgegebenen Objekte gleich sind.

Sei bind-partial entweder std::bind_front oder std::bind_back.

Das zurückgegebene Objekt hat die folgenden Eigenschaften

bind-partial Rückgabetyp

Member-Objekte

Das zurückgegebene Objekt verhält sich so, als ob es enthält

1,3) Ein Member-Objekt fd vom Typ std::decay_t<F>, direkt-nicht-list-initialisiert aus std::forward<F>(f), und
1-4) Ein std::tuple-Objekt tup, konstruiert mit std::tuple<std::decay_t<Args>...>(std::forward<Args>(args)...), außer dass das Verhalten der Zuweisung 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-/Move-Konstruktoren eine elementweise Kopie/Verschiebung durchführen. Er ist CopyConstructible, wenn alle seine Member-Objekte (wie oben angegeben) CopyConstructible sind, und ist andernfalls MoveConstructible.

Member-Funktionsoperator ()

Gegeben sei ein Objekt G, das durch einen früheren Aufruf von (1,3) bind-partial(f, args...) oder (2,4) bind-partial<ConstFn>(args...) erhalten wurde. Wenn ein L-Wert g, der G bezeichnet, in einem Funktionsaufrufausdruck g(call_args...) aufgerufen wird, findet eine Invocierung des gespeicherten Objekts statt, als ob durch:

1) std::invoke(g.fd, std::get<Ns>(g.tup)..., call_args...), wenn bind-partial std::bind_front ist,
2) std::invoke(ConstFn, std::get<Ns>(g.tup)..., call_args...), wenn bind-partial std::bind_front ist,
3) std::invoke(g.fd, call_args..., std::get<Ns>(g.tup)...), wenn bind-partial std::bind_back ist,
4) std::invoke(ConstFn, call_args..., std::get<Ns>(g.tup)...), wenn bind-partial std::bind_back ist,

wobei

  • Ns ist ein Integer-Pack 0, 1, ..., (sizeof...(Args) - 1),
  • g ist ein L-Wert im std::invoke-Ausdruck, wenn es ein L-Wert im Aufrufausdruck ist, und ansonsten ein R-Wert. Daher kann std::move(g)(call_args...) die gebundenen Argumente in den Aufruf verschieben, während g(call_args...) kopiert.

Das Programm ist ill-formed, 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 behält die Ausnahmespezifikation des zugrundeliegenden Aufrufoperators).

[edit] Ausnahmen

1,3) Wirft jede Ausnahme, die beim Aufruf des Konstruktors des gespeicherten Funktionsobjekts geworfen wird.
1-4) Wirft jede Ausnahme, die beim Aufruf des Konstruktors eines der gebundenen Argumente geworfen wird.

[edit] Hinweise

Diese Funktions-Templates sind dazu gedacht, std::bind zu ersetzen. Im Gegensatz zu std::bind unterstützen sie keine beliebige Argumentumordnung und haben keine spezielle Behandlung für verschachtelte Bind-Ausdrücke oder std::reference_wrapper. Andererseits achten sie auf die Wertkategorie des Call-Wrapper-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 Smart Pointern wie std::shared_ptr und std::unique_ptr) auf ein Objekt sein, dessen Mitglied zugegriffen werden soll.

Die Argumente für std::bind_front oder std::bind_back werden kopiert oder verschoben und niemals per Referenz übergeben, es sei denn, sie sind in std::ref oder std::cref eingehüllt.

Typischerweise erfordert das Binden von Argumenten an eine Funktion oder eine Member-Funktion mithilfe von (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 "Nullkosten" in diesen Fällen zu garantieren, führt C++26 die Versionen (2,4) ein (die das aufrufbare Objekt als Argument für einen Nicht-Typ-Template-Parameter akzeptieren).

Feature-Test-Makro Wert Std Feature
__cpp_lib_bind_front 201907L (C++20) std::bind_front, (1)
202306L (C++26) Erlaubt das Übergeben von aufrufbaren Objekten als Nicht-Typ-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 Nicht-Typ-Template-Argumente an std::bind_back, (4)

[edit] 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> 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 { /* is the same as above */ }
 
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)...);
        };
}

[edit] 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); // equivalent to: 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-specification is preserved:
    static_assert(!noexcept(fifty_minus(3)));
    static_assert(noexcept(member_minus(3)));
 
    // Binding of a lambda:
    auto plus = [](int a, int b) { return a + b; };
    auto forty_plus = std::bind_front(plus, 40);
    assert(forty_plus(7) == 47); // equivalent to: 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
}

[edit] Referenzen

  • C++26 Standard (ISO/IEC 14882:2026)
  • TBD Function templates bind_front and bind_back [func.bind.partial]
  • C++23 Standard (ISO/IEC 14882:2024)
  • 22.10.14 Function templates bind_front and bind_back [func.bind.partial]
  • C++20 Standard (ISO/IEC 14882:2020)
  • 20.14.14 Function template bind_front [func.bind.front]

[edit] Siehe auch

(C++11)
bindet ein oder mehrere Argumente an ein Funktions-Objekt
(Funktions-Template) [bearbeiten]
(C++11)
erstellt ein Funktions-Objekt aus einem Zeiger auf ein Member
(Funktions-Template) [bearbeiten]