University of Cambridge >  Engineering Department >  computing help >  Languages >  C++

C++ bind1st and bind2nd

This document aims to help you understand bind1st and bind2nd, which may seem a rather odd and arbitrary objective, but

C++ is quite a strongly typed language - if a function requires an argument of type int and you provide a string, the compiler will complain. This is a good thing in that errors are reduced but it makes generic code (code which will work with different types of arguments) harder to write. Some of the apparent complexity of C++ (bind1st, for example) is due to the methods required to resolve this conflict of needs.

Templates

Templates can help with producing generic code. Consider the following simple routine.

   bool greater_than(int a, int b){
      return a>b;
   }
The basic code would be the same if the arguments were floating point numbers or even strings, but because C++ is fussy about types we'd have to write a separate routine for each type, replacing int each time. This is where templates prove useful
   template <class T>
   bool greater_than(T a, T b){
      return a>b;
   }
This uses the same basic code as the earlier example but instead of int we have T, which at compile time is replaced by whatever is required by subsequent code. So
   int a=6, b=9;
   string s="apple", t="pear";
   cout << greater_than(a,b);
   cout << greater_than(s,t);
will work, the compiler creating the appropriate code. If we try
   greater_than(a,t);
however, compilation won't work, so we haven't compromised on safety.

Using standard library routines

The standard library makes heavy use of templates internally, making it possible to use generic routines without having to learn all the template-related syntax. A little knowledge can go a long way. For example, in the code below,

Note how find is used in the same way whether you're search for characters or integers.
    string s="apple";
    vector<int> v(3);
    v[0]=1; v[1]=2; v[2]=3; 
    // the following line checks if find returns s.end()
    cout << (find(s.begin(),s.end(),'l') != s.end()) << endl;
    cout << (find(v.begin(),v.end(),4) != v.end()) << endl;
Another routine is find_if which is like find except that it doesn't take a value as its 3rd argument. Instead it needs the name of a predicate - a routine which is given an element and returns true only for elements which fulfill the required condition. This offers more flexibility but before we exploit that, let's replicate what the previous example does, dealing with the integer case first.
   bool equal_to_4(int it)
   {
     return it==4;
   }

    vector<int> v(3);
    v[0]=1; v[1]=2; v[2]=3; 

    cout << (find_if(v.begin(),v.end(), equal_to_4)!= v.end())   << endl;
    v[1]=4;
    cout << (find_if(v.begin(),v.end(), equal_to_4)!= v.end())  << endl;
find_if finds the first instance. Now we'll use another standard library routine, count_if, which counts the instances, incrementing the 4th argument accordingly
   bool equal_to_4(int it)
   {
     return it==4;
   }

    int how_many=0;
    vector<int> v(3);
    v[0]=1; v[1]=2; v[2]=3; 

    count_if(v.begin(),v.end(), equal_to_4, how_many);
    cout << how_many << endl;
    v[1]=4;
    how_many=0;
    count_if(v.begin(),v.end(), equal_to_4, how_many);
    cout << how_many << endl;
It's now a small step to be able to count how many elements are greater than 2.
   bool greater_than_2(int it)
   {
     return it>2;
   }

    int how_many=0;
    vector<int> v(3);
    v[0]=1; v[1]=2; v[2]=3; 

    count_if(v.begin(),v.end(), greater_than_2, how_many);
    cout << how_many << endl;
    v[0]=4;
    how_many=0;
    count_if(v.begin(),v.end(), greater_than_2, how_many);
    cout << how_many << endl;
There's another way to do this using functors. When you create a new class you can define what "+" does for objects of that class. Other operators can be defined too. Objects with "()" defined are called function objects or functors. Here's a simple example
   class more_than_2 {
   public:
     bool operator() (int val) {return val>2;}
   };
which we can use with count_if
   count_if(v.begin(),v.end(), more_than_2() , how_many);

Nearly there

Time to take stock. We first used find to look for particular values in collections of elements. We progressed onto using count_if to count the number of elements that match a particular condition. And all without using loops! But on the way we've lost some generic behaviour (I've silently dropped the string handling). Worse still, if we wanted to count how many values were more than 3, we'd not only have to change the count_if call, but also write another routine greater_than_3. We'd like the predicate to take 2 arguments (the element, and the value we're comparing it with) but because of strong-typing, count_if would complain (the predicate should take only 1 argument). So what can we do?

When we used templates earlier to write the greater_than routine, a different version of source code was produced (behind the scenes by the compiler) for each new type of argument used. It's possible to do a similar thing so that functions like our greater_than_2 can be generated on demand. We'll do this in 2 ways - first using a comparison function of our own, then using a standard routine.

Other Functors

greater is only one of several functors in <functional>. They all take 2 arguments They're all used in the same way. So for example, if you wanted to divide all the floats in a vector by 3, you could use
    transform(v.begin(),v.end(),bind2nd(divides<float>(), 3));

Technical Details

The above description glosses over some details.

Both bind1st() and bind2nd() are functions that take as arguments a binary function object and a value, and return, respectively, classes binder1st and binder2nd. The underlying function object must be derived from binary_function.

binder2nd is a function object adaptor: if f is an object of class binder2nd<AdaptableBinaryFunction>, then f(x) returns F(x, c), where F is an object of class AdaptableBinaryFunction and where c is a constant. Both F and c are passed as arguments to binder2nd's constructor.

The easiest way to create a binder2nd is not to call the constructor explicitly, but instead to use the helper function bind2nd.

Definitions

© Cambridge University Engineering Dept
Information provided by Tim Love (tpl)
Last updated: November 2006