std:: bind
|
헤더 파일에 정의됨
<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
인 경우
Args
내의 어떤 타입
Arg_i
에 대해서든, 프로그램은 형식에 맞지 않습니다.
만약
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
입니다. 해당 타입은 다음 멤버들을 정의합니다:
멤버 타입
|
(C++20 이전) |
멤버 함수
operator()
g 가 함수 호출 표현식 g ( u1, u2, ... uM ) 에서 호출될 때, 저장된 객체의 호출이 다음과 같이 수행됩니다.
INVOKE
(
fd,
std::
forward
<
V1
>
(
v1
)
,
std::
forward
<
V2
>
(
v2
)
, ...,
std::
forward
<
VN
>
(
vN
)
)
, 또는
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)
|
가변 개수의 인수를 함수 객체에 순서대로 바인딩
(함수 템플릿) |
|
(C++11)
|
std::bind
표현식에서 바인딩되지 않은 인수들을 위한 플레이스홀더
(상수) |
|
(C++11)
|
멤버 포인터로부터 함수 객체 생성
(함수 템플릿) |