Chapter 11. Boost Libraries

Table of Contents

Bind
Usage of bind
Function objects
Example
Reference wrapper
Tuple
Tuple construction
Tuple operations
Input/Output
Array
Usage
Design

Bind

boost::bind is a generalization of the standard functions std::bind1st and std::bind2nd. It supports arbitrary function objects, functions, function pointers, and member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions. Bind does not place any requirements on the function object; in particular, it does not need the result_type, first_argument_type and second_argument_type standard typedefs.

Example:


int f(int a, int b)
{
    return a + b;
}

int g(int a, int b, int c)
{
    return a + b + c;
}

Usage of bind

bind(f, 1, 2) will produce a "nullary" function object that takes no arguments and returns f(1, 2). Similarly, bind(g, 1, 2, 3)() is equivalent to g(1, 2, 3).

It is possible to selectively bind only some of the arguments.


bind(f, _1, 5)(x)  /* is equivalent to */  f(x, 5)

Here _1 is a placeholder argument that means "substitute with the first input argument."

The same with the older version:


std::bind2nd(std::ptr_fun(f), 5)(x);

More complex solutions:


bind(f, _2, _1)(x, y);                 // f(y, x)
bind(g, _1, 9, _1)(x);                 // g(x, 9, x)
bind(g, _3, _3, _3)(x, y, z);          // g(z, z, z)
bind(g, _1, _1, _1)(x, y, z);          // g(x, x, x)

Note that, in the last example, the function object produced by bind(g, _1, _1, _1) does not contain references to any arguments beyond the first, but it can still be used with more than one argument. Any extra arguments are silently ignored, just like the first and the second argument are ignored in the third example.

The argumenst are copies. If we want to use references, we need helper functions:


int i = 5;

bind(f, i, _1);
bind(f, ref(i), _1);

Function objects

The bind is not limited to functions; it accepts arbitrary function objects. In the general case, the return type of the generated function object's operator() has to be specified explicitly (without a typeof operator the return type cannot be inferred):


struct F
{
    int operator()(int a, int b) { return a - b; }
    bool operator()(long a, long b) { return a == b; }
};

F f;

int x = 104;
bind<int>(f, _1, _1)(x);   // f(x, x), i.e. zero  

int x = 8;
bind(std::less<int>(), _1, 9)(x);    // x < 9

Example


class image;

class animation
{
public:

    void advance(int ms);
    bool inactive() const;
    void render(image & target) const;
};

std::vector<animation> anims;

template<class C, class P> void erase_if(C & c, P pred)
{
    c.erase(std::remove_if(c.begin(), c.end(), pred), c.end());
}

void update(int ms)
{
    std::for_each(anims.begin(), anims.end(), boost::bind(&animation::advance, _1, ms));
    erase_if(anims, boost::mem_fn(&animation::inactive));
}

void render(image & target)
{
    std::for_each(anims.begin(), anims.end(), boost::bind(&animation::render, _1, boost::ref(target)));
}

Reference wrapper

The header boost/ref.hpp defines the class template boost::reference_wrapper<T>, the two functions boost::ref and boost::cref that return instances of boost::reference_wrapper<T>, and the two traits classes boost::is_reference_wrapper<T> and boost::unwrap_reference<T>.

The purpose of boost::reference_wrapper is to contain a reference to an object of type T. It is primarily used to "feed" references to function templates (algorithms) that take their parameter by value.

To support this usage, boost::reference_wrapper provides an implicit conversion to T &. This usually allows the function templates to work on references unmodified.


namespace boost
{
    template<class T> class reference_wrapper;
    template<class T> reference_wrapper<T> ref(T & t);
    template<class T> reference_wrapper<T const> cref(T const & t);
    template<class T> class is_reference_wrapper<T const>;
    template<class T> class unwrap_reference<T const>;
}

Implementation is trivial


template<class T> class reference_wrapper
{
public:
    typedef T type;
    explicit reference_wrapper(T & t);

    operator T & () const;

    T & get() const;
    T* get_pointer() const;
private:
    T* t_;
};