Namespaces
Variants

std::bind_front, std::bind_back

cppreference.net에서
 
 
유틸리티 라이브러리
일반 유틸리티
관계 연산자 (C++20에서 폐지됨)
정수 비교 함수
(C++20)(C++20)(C++20)    
(C++20)
스왑 및 타입 연산
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
공통 어휘 타입
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)



 
함수 객체
함수 호출
(C++17)(C++23)
항등 함수 객체
(C++20)
투명 연산자 래퍼
(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)

이전의 바인더와 어댑터
(C++17까지*)
(C++17까지*)
(C++17까지*)
(C++17까지*)  
(C++17까지*)
(C++17까지*)(C++17까지*)(C++17까지*)(C++17까지*)
(C++20까지*)
(C++20까지*)
(C++17까지*)(C++17까지*)
(C++17까지*)(C++17까지*)

(C++17까지*)
(C++17까지*)(C++17까지*)(C++17까지*)(C++17까지*)
(C++20까지*)
(C++20까지*)
 
헤더 <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는 완벽 전달 호출 래퍼를 생성합니다. 이 래퍼는 호출 가능 대상을 호출할 때 (1,2) 처음 개 또는 (3,4)sizeof...(Args) 마지막 args 개의 매개변수를

에 바인딩합니다. (1,3) 호출 래퍼는 대상 호출 가능 객체 f의 복사본을 보유합니다.
(2,4) 호출 래퍼는 호출 가능 대상을 보유하지 않습니다 (정적으로 결정됩니다).
(1) std::bind_front(f, bound_args...)(call_args...)은(는) 표현식 동등합니다:
std::invoke(f, bound_args..., call_args...).
(2) std::bind_front<ConstFn>(bound_args...)(call_args...)은(는) 표현식 동등합니다:
std::invoke(ConstFn, bound_args..., call_args...).
(3) std::bind_back(f, bound_args...)(call_args...)은(는) 표현식 동등합니다:
std::invoke(f, call_args..., bound_args...).
(4) std::bind_back<ConstFn>(bound_args...)(call_args...)은(는) 표현식 동등합니다:
std::invoke(ConstFn, call_args..., bound_args...).

다음 조건이 충족되어야 true하며, 그렇지 않으면 프로그램의 형식이 잘못되었습니다(ill-formed):

  • (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 반환 타입

멤버 객체

반환된 객체는 다음과 같이 보유하는 것처럼 동작합니다:

1,3) 멤버 객체 fd 가 타입 std:: decay_t < F > 로부터 std:: forward < F > ( f ) 를 사용하여 직접-비목록-초기화되고, 그리고
1-4) std::tuple 객체 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... ) 에서 호출되면, 저장된 객체의 호출이 다음과 같이 수행됩니다:

1) std:: invoke ( g. fd , std :: get < Ns > ( g. tup ) ..., call_args... ) , bind-partial 이 std::bind_front 인 경우,
2) std:: invoke ( ConstFn, std :: get < Ns > ( g. tup ) ..., call_args... ) , bind-partial 가 std::bind_front 인 경우
3) std:: invoke ( g. fd , call_args..., std :: get < Ns > ( g. tup ) ... ) , bind-partial 이 std::bind_back 인 경우,
4) std:: invoke ( ConstFn, call_args..., std :: get < Ns > ( g. tup ) ... ) , 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인 경우 (다시 말해, 기본 호출 연산자의 예외 명세를 보존합니다).

예외

1,3) 저장된 함수 객체의 생성자를 호출하여 발생하는 모든 예외를 throw합니다.
1-4) 바인딩된 인수 중 어떤 것의 생성자를 호출할 때 발생하는 모든 예외를 던집니다.

참고 사항

이 함수 템플릿들은 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)