Namespaces
Variants

std::bind

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>
template< class F, class... Args >
/* unspecified */ bind( F&& f, Args&&... args );
에 정의됨 (1) (C++11부터)
(C++20부터 constexpr)
template< class R, class F, class... Args >
/* unspecified */ bind( F&& f, Args&&... args );
(2) (C++11부터)
(C++20부터 constexpr)

함수 템플릿 std::bind은 f에 대한 전달 호출 래퍼를 생성합니다. 이 래퍼를 호출하는 것은 해당 인수의 일부를 f바인딩하여 args를 호출하는 것과 동일합니다.

std::is_constructible<std::decay<F>::type, F>::value이 false이거나, std::is_constructible<std::decay<Arg_i>::type, Arg_i>::value의 어떤 타입 false에 대해 Arg_i인 Args가 있는 경우, 프로그램은 ill-formed입니다.

std::decay<Ti>::type 또는 Args의 어떤 타입이 MoveConstructible 또는 Destructible이 아닌 경우, 동작은 정의되지 않습니다.

매개변수

f - Callable 객체 (함수 객체, 함수 포인터, 함수 참조, 멤버 함수 포인터, 또는 데이터 멤버 포인터)로 일부 인수에 바인딩될 대상
args - 바인딩할 인수 목록으로, 바인딩되지 않은 인수들은 placeholders _1 , _2 , _3 ...로 대체됨 (네임스페이스 std::placeholders 소속)

반환값

지정되지 않은 타입 T 의 함수 객체 g 에 대해, std:: is_bind_expression < T > :: value 가 true 인 경우. 다음과 같은 멤버들을 가집니다:

std::bind 반환 타입

멤버 객체

std::bind 의 반환 타입은 std:: decay < F > :: type 타입의 멤버 객체를 보유하며, 이 객체는 std:: forward < F > ( f ) 로부터 생성됩니다. 또한 args... 각각에 대해 하나의 객체를 보유하며, 이 객체들의 타입은 std:: decay < Arg_i > :: type 이고, 이는 std:: forward < Arg_i > ( arg_i ) 로부터 유사하게 생성됩니다.

생성자

std::bind 의 반환 타입은 CopyConstructible 입니다 - 위에 명시된 모든 멤버 객체가 CopyConstructible일 경우에 한하며, 그렇지 않은 경우에는 MoveConstructible 입니다. 해당 타입은 다음 멤버들을 정의합니다:

멤버 타입 result_type

1) (C++17에서 deprecated 됨) 만약 F 가 함수 포인터 또는 멤버 함수 포인터인 경우, result_type 은 F 의 반환 타입입니다. 만약 F 가 중첩 typedef result_type 을 가진 클래스 타입이라면, result_type 은 F::result_type 입니다. 그 외의 경우에는 result_type 이 정의되지 않습니다.
2) (C++17에서 deprecated 됨) result_type 은 정확히 R 입니다.
(C++20 이전)

멤버 함수 operator()

g 가 함수 호출 표현식 g ( u1, u2, ... uM ) 에서 호출될 때, 저장된 객체의 호출이 다음과 같이 수행됩니다.

1) INVOKE ( fd, std:: forward < V1 > ( v1 ) , std:: forward < V2 > ( v2 ) , ..., std:: forward < VN > ( vN ) ) , 또는
2) INVOKE<R> ( fd, std:: forward < V1 > ( v1 ) , std:: forward < V2 > ( v2 ) , ..., std:: forward < VN > ( vN ) ) ,

여기서 fd 는 std:: decay < F > :: type 타입의 값이며, 바인딩된 인수 v1 , v2 , ..., vN 의 값과 타입은 아래 에 명시된 대로 결정됩니다.

g ( ) 호출 시 제공된 인수 중 일부가 g 에 저장된 자리 표시자와 일치하지 않으면, 사용되지 않은 인수들은 평가된 후 폐기됩니다.

operator ( ) 의 호출은, 기반이 되는 INVOKE 연산이 그렇듯이 예외를 발생시키지 않는 경우에만 또는 상수 부분식인 경우에만 (C++20부터) 그렇습니다. operator ( ) 는 INVOKE 연산이 평가되지 않은 피연산자로 취급될 때 올바른 형식인 경우에만 오버로드 해결에 참여합니다.

만약 g 가 volatile -qualified라면, 프로그램은 ill-formed입니다.

만약 INVOKE ( fd, w1, w2, ..., wN ) 표현식이 가능한 모든 값 w1 , w2 , ..., wN 에 대해 유효한 표현식이 될 수 없다면, 동작은 정의되지 않습니다.

바인드된 인수

각 저장된 인수 arg_i 에 대해, INVOKE 또는 INVOKE<R> 연산에서 해당하는 바인딩된 인수 v_i 는 다음과 같이 결정됩니다:

사례 1: 레퍼런스 래퍼

만약 arg_i 가 std:: reference_wrapper < T > 타입인 경우 (예를 들어, std::ref 또는 std::cref 가 std::bind 에 대한 초기 호출에서 사용된 경우), v_i 는 arg_i. get ( ) 이고 그 타입 V_i 는 T& 입니다: 저장된 인자는 참조로 호출된 함수 객체에 전달됩니다.

Case 2: 바인드 표현식

만약 arg_i 가 std:: is_bind_expression < T > :: value 가 true 인 T 타입인 경우(예를 들어, 다른 std::bind 표현식이 std::bind 의 초기 호출에 직접 전달된 경우), std::bind 는 함수 합성을 수행합니다: 바인드 하위 표현식이 반환할 함수 객체를 전달하는 대신, 하위 표현식이 즉시 호출되고 그 반환 값이 외부 호출 가능 객체에 전달됩니다. 바인드 하위 표현식에 placeholder 인자가 있는 경우, 이들은 외부 바인드와 공유됩니다( u1 , u2 , ... 에서 선택됨). 구체적으로, v_i 는 arg_i ( std:: forward < Uj > ( uj ) ... ) 이고 그 타입 V_i 는 std:: result_of < T cv  & ( Uj && ... ) > :: type && (C++17 이전) std:: invoke_result_t < T cv  & , Uj && ... > && (C++17 이후) 입니다(cv 한정자는 g 와 동일함).

Case 3: 플레이스홀더

만약 arg_i 가 T 타입이고, 이에 대해 std:: is_placeholder < T > :: value 가 ​ 0 ​ 이 아닌 경우(즉, std::placeholders::_1, _2, _3, ... 와 같은 플레이스홀더가 std::bind 에 대한 초기 호출의 인수로 사용된 경우), 해당 플레이스홀더가 나타내는 인수( _1 에 대한 u1 , _2 에 대한 u2 등)가 호출 가능 객체에 전달됩니다: v_i 는 std:: forward < Uj > ( uj ) 이며, 그 타입 V_i 는 Uj&& 입니다.

Case 4: 일반 인수

그렇지 않으면, arg_i 가 호출 가능 객체에 lvalue 인수로 전달됩니다: v_i 는 단순히 arg_i 이고, 그 타입 V_i 는 T cv  & 입니다. 여기서 cv 는 g 의 cv 한정자와 동일합니다.

예외

std:: decay < F > :: type 을 std:: forward < F > ( f ) 에서 생성하는 과정에서 예외가 발생하거나, std:: decay < Arg_i > :: type 의 생성자 중 어느 하나가 해당하는 std:: forward < Arg_i > ( arg_i ) 에서 예외를 발생시킬 때만 예외를 발생시킵니다. 여기서 Arg_i 는 i번째 타입이고 arg_i 는 Args... args 에서 i번째 인자입니다.

참고 사항

Callable 에서 설명된 바와 같이, 비정적 멤버 함수 포인터나 비정적 데이터 멤버 포인터를 호출할 때 첫 번째 인수는 해당 멤버에 접근할 객체의 참조나 포인터( std::shared_ptr 및 std::unique_ptr 와 같은 스마트 포인터 포함)여야 합니다.

bind에 전달된 인수들은 복사되거나 이동되며, std::ref 또는 std::cref 로 래핑되지 않는 한 참조로 전달되지 않습니다.

동일한 바인드 표현식 내에서 중복된 플레이스홀더(예를 들어 여러 개의 _1 )는 허용되지만, 해당 인수( u1 )가 lvalue 또는 이동 불가능한 rvalue인 경우에만 결과가 명확하게 정의됩니다.

예제

#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;  // for _1, _2, _3...
    std::cout << "1) 인수 재정렬 및 참조에 의한 전달: ";
    int n = 7;
    // (_1과 _2는 std::placeholders에 있으며, 미래의
    // f1에 전달될 인수들)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1은 _1에 바인딩되고, 2는 _2에 바인딩되며, 1001은 사용되지 않음
                    // f(2, 42, 1, n, 7) 호출을 수행합니다
    std::cout << "2) 람다를 사용하여 동일한 효과 달성: ";
    n = 7;
    auto lambda = [&ncref = n, n](auto a, auto b, auto /*사용되지 않음*/)
    {
        f(b, 42, a, ncref, n);
    };
    n = 10;
    lambda(1, 2, 1001); // f1(1, 2, 1001) 호출과 동일함
    std::cout << "3) 중첩된 bind 하위 표현식은 플레이스홀더를 공유합니다: ";
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // f(12, g(12), 12, 4, 5) 호출을 수행합니다;
    std::cout << "4) RNG를 분포와 바인딩하기: ";
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    auto rnd = std::bind(d, e); // e의 복사본이 rnd에 저장됨
    for (int n = 0; n < 10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';
    std::cout << "5) 멤버 함수 포인터에 바인딩: ";
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);
    std::cout << "6) 멤버 함수 포인터인 mem_fn에 바인딩: ";
    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) 데이터 멤버에 대한 포인터에 바인딩: ";
    auto f5 = std::bind(&Foo::data, _1);
    std::cout << f5(foo) << '\n';
    std::cout << "8) 데이터 멤버에 대한 포인터인 mem_fn에 바인딩: ";
    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) 참조된 객체의 멤버를 호출하기 위해 스마트 포인터를 사용하십시오: ";
    std::cout << f6(std::make_shared<Foo>(foo)) << ' '
              << f6(std::make_unique<Foo>(foo)) << '\n';
}

출력:

1) 인수 재정렬 및 참조에 의한 전달: 2 42 1 10 7
2) 람다를 사용하여 동일한 효과 달성: 2 42 1 10 7
3) 중첩된 bind 하위 표현식은 플레이스홀더를 공유함: 12 12 12 4 5
4) 분포를 가진 RNG 바인딩: 0 1 8 5 5 2 0 7 7 10 
5) 멤버 함수 포인터에 바인딩: 100
6) 멤버 함수 포인터인 mem_fn에 바인딩: 100
7) 데이터 멤버 포인터에 바인딩: 10
8) 데이터 멤버 포인터인 mem_fn에 바인딩: 10
9) 참조된 객체의 멤버를 호출하기 위해 스마트 포인터 사용: 10 10

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
LWG 2021 C++11 1. 바운드 인수들이
fd 로 전달되지 않음
2. 경우 2에서, V_i 의 타입이
std:: result_of < T cv  ( Uj... ) > :: type 임
1. 전달됨
2. 다음으로 변경됨
std:: result_of < T cv  & ( Uj && ... ) > :: type &&

참고 항목

(C++20) (C++23)
가변 개수의 인수를 함수 객체에 순서대로 바인딩
(함수 템플릿)
std::bind 표현식에서 바인딩되지 않은 인수들을 위한 플레이스홀더
(상수)
(C++11)
멤버 포인터로부터 함수 객체 생성
(함수 템플릿)