How the binding function works for functional objects in C ++

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 have a doubt that how bind (more (), _ 1, x) and bind (less (), _ 1, y) are evaluated and return 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 functors are called inside the bind function. Can someone explain how this works? Thanks in advance.

+6
source share
1 answer

To understand this, we need 1 st to understand how bind binds its arguments. Given that g is the result of the bind expression, which is called using: g(u1, u2, ... uM) :

  • If the stored arg argument is of type std::reference_wrapper<T> (for example, std::ref or std::cref was used in the first call to bind), then the vn argument in the call to std::invoke above arg.get() and type vn in the same T& call: the stored argument is passed by reference to the called function object.
  • If the stored arg argument is of type T , for which std::is_bind_expression<T>::value == true (which means that another binding expression was passed directly to the original call for binding), then the binding performs the composition function: instead of passing the function, the object to which the bind subexpression returns, the subexpression is invoked impatiently, and its return value is passed to the external called object. If the binding subexpression has any placeholder arguments, they are separated by an external binding (selected from u1 , u2 , ...). In particular, the argument vn in the above call to std::invoke is arg(std::forward<Uj>(uj)...) , and the type vn in the same call is std::result_of_t<T cv &(Uj&&...)>&& (cv-qualification is the same as g ).
  • If the stored argument arg is of type T for which std::is_placeholder<T>::value != 0 , that is, a placeholder such as std::placeholders::_1 , _2 , _3 , was used as an argument for the initial value. .. call for binding), then the argument specified by the placeholder ( u1 for _1 , u2 for _2 , etc.) is passed to the calling object: the vn argument in the call to std::invoke above std::forward<Uj>(uj) , and the corresponding type vn in the same call is Uj&& .
  • Otherwise, the normal argument arg argument is passed to the caller as the lvalue argument: the vn argument in the call to std::invoke above is just arg, and the corresponding vn type is T cv & , where cv > is the same cv qualification as for g .

The key is in a bunch of 2 nd . Since binding expressions are invoked during binding, this works:

 std::cout << std::bind(std::logical_and<bool>(), fn1, fn2)() 

But since there is no & operator for binding expressions, this will not work:

 std::cout << std::logical_and<bool>()(fn1, fn2)() 
+5
source

All Articles