I came across the following find_if function.
find_if (coll.begin(), coll.end(),
bind(logical_and<bool>(),
bind(greater<int>(),_1,x), bind(less<int>(),_1,y)
)
);
I've the doubt that how the bind(greater(),_1,x) and bind(less(),_1,y) are evaluated and returning bool values there? This will not work otherwise as shown below.
#include <iostream>
#include <functional>
int main()
{
using namespace std::placeholders;
//auto fn = std::bind(std::greater<int>(), 5, _1);
//std::cout << fn(7) << std::endl;
//std::cout << typeid(fn).name() << std::endl;
auto fn1 = std::bind(std::greater<int>(),5,6);
auto fn2 = std::bind(std::less<int>(),7,5);
std::cout << std::bind( std::logical_and<bool>(), fn1, fn2 )(); // how this works??
std::cout << std::logical_and<bool>()(fn1, fn2)(); // Compilation error
}
Really curious to know how the functors are called inside the bind function. Can someone please explain how this works? Thanks in advance.
To understand this we'll need to 1st understand how bind
, binds it's arguments. Given that g
is the result of a bind
expression which is called with: g(u1, u2, ... uM)
:
- If the stored argument arg is of type
std::reference_wrapper<T>
(for example,std::ref
orstd::cref
was used in the initial call to bind), then the argumentvn
in thestd::invoke
call above isarg.get()
and the typeVn
in the same call isT&
: the stored argument is passed by reference into the invoked function object.- If the stored argument arg is of type
T
for whichstd::is_bind_expression<T>::value == true
(meaning, another bind expression was passed directly into the initial call to bind), then bind performs function composition: instead of passing the function object that the bind subexpression would return, the subexpression is invoked eagerly, and its return value is passed to the outer invokable object. If the bind subexpression has any placeholder arguments, they are shared with the outer bind (picked out ofu1
,u2
, ...). Specifically, the argumentvn
in thestd::invoke
call above isarg(std::forward<Uj>(uj)...)
and the typeVn
in the same call isstd::result_of_t<T cv &(Uj&&...)>&&
(cv qualification is the same as that ofg
).- If the stored argument arg is of type
T
, for whichstd::is_placeholder<T>::value != 0
, meaning, a placeholder such asstd::placeholders::_1
,_2
,_3
, ... was used as the argument to the initial call to bind), then the argument indicated by the placeholder (u1
for_1
,u2
for_2
, etc) is passed to the invokable object: the argumentvn
in thestd::invoke
call above isstd::forward<Uj>(uj)
and the corresponding typeVn
in the same call isUj&&
.- Otherwise, the ordinary stored argument arg is passed to the invokable object as lvalue argument: the argument
vn
in thestd::invoke
call above is simply arg and the corresponding typeVn
isT cv &
, wherecv
is the same cv-qualification as that ofg
.
The key is in the 2nd bullet. Because the bind expressions are invoked at binding time this works:
std::cout << std::bind(std::logical_and<bool>(), fn1, fn2)()
But because there is no &
operator defined for bind expressions, this won't work:
std::cout << std::logical_and<bool>()(fn1, fn2)()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With