bind
Function TemplateOne Ring to bring them all and in the darkness bind them.
The Fellowship of the Ring
J.R.R. TOLKIEN
Suppose that you have a pair of pointers, first
and last
, defining a sequence of integer values, and you need to know how many elements in the sequence have a value that is greater than or equal to 10. You can do this with the standard algorithm count_if
and a predicate that returns true when called with a value that is greater than or equal to 10. The standard library doesn’t have that predicate, but it has less
, which takes two arguments and returns true if the first argument is less than the second. If you had a way to tell count_if
to always use 10 as the first argument to the less
predicate, you’d have the problem solved. That’s a simple example of what the TR1 template function bind
can do.
Example 10.1. Simple bind Example (funobjbind/simple.cpp
)
#include <functional>
#include <iostream>
using std::tr1::bind;
using namespace std::tr1::placeholders;
using std::less; using std::cout;
template <class Pr>
int count_elements(const int *first, const int *last,
Pr pred)
{ // count elements in the range [first, last) for which pred(elt) is true
int count = 0;
while (first != last)
if (pred(*first++))
++count;
return count;
}
int count_ge10(int *first, int *last)
{ // bind 10 as first argument to less<int>
int val = 10;
return count_elements(first, last,
bind(less<int>(), val, _1));
}
int main()
{ // demonstrate simple uses of bind
int values[6] = { 1, 3, 19, 12, 6, 11 };
int count = count_ge10(values, values + 6);
cout << count
<< "values greater than or equal to 10
";
return 0;
}
The function count_ge10
calls bind
with three arguments. The first is the target object. Its type is less<int>
, and it has a function call operator that takes two arguments of type int
. The second argument is val
, with a value of 10. Because it’s the first argument after the target object, it tells bind
what the first argument to the target object should be. When the object returned by bind
is called, the value val
will be passed as the first argument to the target object. The third argument is the placeholder _1
. Because it’s the second argument after the target object, it tells bind
what the second argument to the target object should be. The placeholder _1
says that this argument should be the value passed as the first argument when the bind
object is called. The resulting bind
object is then passed as the predicate to the function template count_elements
.[1]
The function template count_elements
steps through the elements of its input range, passing each element in turn to the predicate pred
and incrementing count
each time the call to pred
returns true. In this example, the call to pred(*first++)
does the same thing as this code:
less<int> pr;
pr(10, *first++);
That is, the call to bind
has bound the value 10 as the first argument to less<int>
, producing a predicate that can be called with a single argument of type int
that returns true if the value of its argument is greater than or equal to 10.
The function template bind
takes a callable object as its first argument and returns a call wrapper whose target object is a copy of the callable object. The function template also takes additional arguments that describe the arguments that will be passed to the target object when it is called. When the additional argument is a value, that value is passed when the target object is called. When the additional argument is a placeholder, the value passed to the bind
object’s function call operator is passed to the target object. This lets you turn a function object that takes two arguments into a function object that takes one argument, with a fixed value for its other argument.
namespace std {
namespace tr1 {
namespace placeholders {
extern unspecified _1;
extern unspecified _2;
extern unspecified _3;
} } }
Placeholder types have default constructors and copy constructors that do not throw exceptions. The types are not required to support assignment, but if they do, their assignment operators do not throw exceptions.
As we’ll see in the next section, placeholders are passed as arguments to the bind
function template to designate argument values that will be supplied later. The placeholders supplied in the TR1 library are named _1
, _2
, and so on, up to the maximum value supported by the implementation. You can also supply your own placeholders, although you’ll probably never need to do this. If you do, see Section 10.3 for an explanation of how to do it.
bind(…..)
template <class Fty, class T1, class T2, …, class TN>
unspecified bind(Fty fn, T1 t1, T2 t2, …, TN tn);
template <class Ret,
class Fty, class T1, class T2, …, class TN>
unspecified bind(Fty fn, T1 t1, T2 t2, …, TN tn);
The first function returns a forwarding call wrapper (see Section 6.1) wrap
that has a weak result type (see Section 6.2). Calling wrap(u1, u2, …, uM)
returns INVOKE_R (fn, v1, v2, …, vn, Ret)
, where cv
represents the cv-qualifiers of wrap
, the values v1, v2, …, vN
and their types V1, V2, …, VN
are determined by the rules for bound types, and Ret
is the type named by result_of<Fty cv (V1, V2, …, VN)>::type)
.
The second function returns a forwarding call wrapper (see Section 6.1) wrap
that has a nested type named result_type
that is a synonym for the template argument Ret
. Calling wrap(u1, u2, …, uM)
returns INVOKE_R (fn, v1, v2, …, vn, Ret)
, where cv
represents the cv-qualifiers of wrap
, and the values v1, v2, …, vN
and their types V1, V2, …, VN
are determined by the rules for bound types.
For both functions, the types Fty
, T1
, …, TN
must be copy constructible, and a set of values w1, w2, …, wN
must exist for which INVOKE (fn, w1, w2, …, wN)
is a valid expression.
The bound arguments v1, v2, …, vN
and their types V1, V2, …, VN
are determined by the type of the corresponding argument ti
and its type Ti
in the call to bind
and by the cv-qualifiers cv
of the call wrapper wrap
. The value and type of the argument vi
are determined by the first of the following four rules that applies.
1. If the type of ti
is reference_wrapper<T>
for some T
, the argument vi
is ti.get()
, and its type Vi
is T&
.
2. If the value of std::tr1::is_bind_expression<Ti>::value
is true, the argument vi
is ti(u1, u2, …, uM)
, and its type Vi
is result_of<Ti
cv (U1&, U2&, …, UM&)>::type
.
3. If the value j
of std::tr1::is_placeholder<Ti>::value
is not zero, the argument vi
is uj
, and its type Vi
is Uj&
.
4. Otherwise, the argument vi
is ti
, and its type Vi
is cv Ti&
.
That’s pretty dense. To sort it out, we’ll look at the additional arguments to bind
, then start at the bottom of the list of rules and work our way up to the top. Keep in mind that three calls and three corresponding argument lists are involved. First is a call to bind
, which returns a call wrapper; second is a call to that call wrapper, which provides additional arguments that can be referred to by placeholder arguments in the call to bind
; and third is a call to the call wrapper’s target object, made by the call wrapper. The types of the arguments in the call to bind
determine how those arguments are treated and, sometimes, how the arguments in the call to the call wrapper are treated.
bind
Every call to bind
must have one argument that is a callable object and as many additional arguments as are needed to call that callable object.
Example 10.2. Additional Arguments (funobjbind/additional.cpp
)
#include <functional>
using std::tr1::bind;
int no_args()
{ // function taking no arguments
return 1;
};
struct one_arg
{ // class type with member operator() taking one argument
int operator()(int i) const
{ // function call operator that takes one argument
return i;
}
typedef int result_type;
};
struct three_args
{ // class type with member function taking two arguments
int f(int i, int j) const
{ // member function taking two arguments
return i + j;
}
};
void call_bind()
{ // examples of calls to bind
// no additional arguments
bind(no_args);
// one additional argument
one_arg a1;
bind(a1, 1);
// three additional arguments
three_args a3;
bind(&three_args::f, a3, 1, 2);
}
In this example, the first call to bind
passes a single argument that is a pointer to the function no_args
. Because no_args
takes no arguments, the call to bind
is made with no additional arguments. The second call to bind
passes a callable object of type one_arg
. Since one_arg
’s function call operator takes one argument, the call to bind
has one additional argument. The third call to bind
passes an argument that is a pointer to a member function of the class three_args
. In order to call the member function, we need one argument that designates the object for the member function and as many more additional arguments as there are arguments to the member function. Since three_-args::f
takes two arguments, the call to bind
must have three additional arguments: the object and the two arguments for three_args::f
.
Under rule 4, arguments that are ordinary types are simply passed to the target object when the bind object is called.
Example 10.3. Rule 4 (funobjbind/rule4.cpp
)
#include <iostream>
#include <functional>
using std::tr1::bind;
using std::cout;
int no_args()
{ // function taking no arguments
return 0;
};
struct one_arg
{ // class type with member operator() taking one argument
int operator()(int i) const
{ // function call operator that takes one argument
return i;
}
typedef int result_type;
};
struct three_args
{ // class type with member function taking two arguments
three_args(int v) : val(v) {}
int f(int i, int j) const
{ // member function taking two arguments
return val + 2 * i + 3 * j;
}
private :
int val;
};
int main()
{ // examples of calls to bind
// no additional arguments
cout << bind(no_args)() << '
';
cout << no_args() << '
'; // equivalent call
// one additional argument
one_arg a1;
cout << bind(a1, 1)() << '
';
cout << a1(1) << '
'; // equivalent call
// three additional arguments
three_args a3(1);
cout << bind(&three_args::f, a3, 2, 3)() << '
';
cout << a3.f(2, 3) << '
'; // equivalent call
return 0;
}
In this example, the three calls to bind
are the same as the calls in the previous example. The main difference here is that the object returned by each of those calls to bind
is then called with no arguments. Calling the returned object in turn calls the target object, passing the arguments given in the original call to bind
.
The first call to bind
passes the function pointer no_args
. The returned object holds a copy of that pointer. Calling the returned object simply calls no_args
, which returns the value 0
. The returned object’s function call operator returns that value, so the program displays the value 0
for this operation.
The second call to bind
passes a callable object of type one_arg
and the value 1
. The returned object holds a copy of the callable object and of the additional argument: in this case, 1
. Calling the returned object in turn calls the target object of type one_arg
with the stored value 1
. The call to the target object returns its argument, and the call of the returned object also returns that value, so the program displays the value 1
for this operation.
The third call to bind
passes a pointer to member function, &three_args::f
, followed by an object of type three_args
and the values 2
and 3
. The returned object holds a copy of each of those four arguments. Calling the returned object calls a.f(2, 3)
, where a
is the stored copy of the object of type three_args
. That member function call returns the value 14
, so the call of the returned object also returns 14
. The program displays the value 14
for this operation.
Under rule 3, if std::tr1::is_placeholder<Ti>::value
is not zero, the value passed to the target object as the argument at position i
is the value passed in the call to the bind
object as the argument at position is_place-holder<Ti>::value
. For the standard placeholders _1
, _2
, and so on, the corresponding values of is_placeholder::value
are 1
, 2
, and so on. So the placeholder _1
says to pass the first argument, _2
says to pass the second argument, and so on. For example:
bind(f, _1)(a, b) // calls f(a)
bind(f, _2)(a, b) // calls f(b)
bind(g, _1, _2)(a, b) // calls g(a, b)
bind(g, _2, _1)(a, b) // calls g(b, a)
bind(g, c, _1)(a, b) // calls g(c, a)
In real code:
Example 10.4. Rule 3 (funobjbind/rule3.cpp
)
#include <iostream>
#include <functional>
using std::tr1::bind;
using namespace std::tr1::placeholders;
using std::cout;
struct one_arg
{ // class type with member operator() taking one argument
int operator()(int i) const
{ // function call operator that takes one argument
return i;
}
typedef int result_type;
};
struct three_args
{ // class type with member function taking two arguments
three_args(int v) : val(v) {}
int f(int i, int j) const
{ // member function taking two arguments
return val + 2 * i + 3 * j;
}
private :
int val;
};
int main()
{ // examples of calls to bind
// argument values
int a = 10;
int b = 11;
int c = 12;
// one additional argument
one_arg a1;
cout << bind(a1, _1)(a, b, c) << '
';
cout << a1(a) << '
'; // equivalent call
cout << bind(a1, _2)(a, b, c) << '
';
cout << a1(b) << '
'; // equivalent call
cout << bind(a1, _3)(a, b, c) << '
';
cout << a1(c) << '
'; // equivalent call
cout << bind(a1, 10)( a, b, c) << '
';
cout << a1(10) << '
'; // equivalent call
// three additional arguments
three_args a3(1);
cout << bind(&three_args::f, a3, _1, _2)(a, b, c)
<< '
';
cout << a3.f(a, b) << '
'; // equivalent call
cout << bind(&three_args::f, a3, _2, _3)(a, b, c)
<< '
';
cout << a3.f(b, c) << '
'; // equivalent call
cout << bind(&three_args::f, a3, _3, _2)(a, b, c)
<< '
';
cout << a3.f(c, b) << '
'; // equivalent call
cout << bind(&three_args::f, a3, 1, _2)(a, b, c)
<< '
';
cout << a3.f(1, b) << '
'; // equivalent call
return 0;
}
You probably noticed in both of the preceding code examples that the call to the object returned by bind
used named variables, not literals. That’s because rule 3 says that the declared type of the argument to the function call operator is Uj&
. In this example, all the Uj
s are of type int
, so the argument types are all int&
s. That’s fine for named variables of type int
but leads to a problem for literals, because you can’t pass a literal value where an int&
is expected.[2] This is an example of what is known as the forwarding problem: It’s very difficult to write a function template that passes its arguments by reference to another function. The problem arises because template arguments of type T
and of type const T
are both treated by the compiler as T
. Ordinarily, that’s what you want: You should be able to call a function that takes an argument of type int
with the value 1
, even though the type of 1
is const int
. But when you want to use a reference to the type, const
matters. The rule in the TR1 library is that you get a non-const
reference, and there’s a suggestion that implementations ought to try to support const
references as well. Unfortunately, doing so in standard C++ requires multiple overloads:
void f(int&, int&);
void f(const int&, int&);
void f(int&, const int&);
void f(const int&, const int&);
This, in turn, requires multiple function templates, one for each combination of const
and non-const
arguments. The number of overloads needed is 2n, where n is the number of arguments. Obviously, this becomes prohibitive as n becomes larger. So don’t count on being able to call bind
objects with constant values.[3]
bind
ArgumentsUnder rule 2, arguments to bind
can themselves be objects returned by calls to bind
. For example:
bind(f, bind(g, a), b)(c, d) // calls f(g(a), b)
bind(f, bind(g, b), _1)(c, d) // calls f(g(b), c)
Any placeholder arguments in nested calls to bind
refer to the arguments in the innermost call to a bind
object that contains the placeholder. For example:
bind(f, bind(g, _1), a)(c, d) // calls f(g(c), a)
bind(f, bind(g, _1), _2)(c, d) // calls f(g(c), d)
bind (f, bind(g, _2)(a, b), _2)(c, d) // calls f(g(b), d)
In real code:
Example 10.5. Rule 2 (funobjbind/rule2.cpp
)
#include <iostream>
#include <functional>
using std::tr1::bind;
using namespace std::tr1::placeholders;
using std::cout;
struct one_arg
{ // class type with member operator() taking one argument
int operator()(int i) const
{ // function call operator that takes one argument
return i;
}
typedef int result_type;
};
struct three_args
{ // class type with member function taking two arguments
three_args(int v) : val(v) {}
int f(int i, int j) const
{ // member function taking two arguments
return val + 2 * i + 3 * j;
}
private :
int val;
};
int main()
{ // examples of calls to bind
// argument values
int a = 10;
int b = 11;
int c = 12;
one_arg a1;
one_arg a2;
three_args a3(2);
// no additional arguments
cout << bind(a1, bind(a2, a))() << '
';
cout << a1(a2(a)) << '
'; // equivalent call
// one additional argument
cout << bind(a1, bind(a2, _1))(b) << '
';
cout << a1(a2(b)) << '
'; // equivalent call
// two additional arguments
cout << bind(a1, bind(a2, _1))(a, b) << '
';
cout << a1(a2(a)) << '
'; // equivalent call
cout << bind(&three_args::f, a3,
bind(a1, _1), bind(a2, _1))(a, b) << '
';
cout << a3.f(a1(a), a2(a)) << '
'; // equivalent call
return 0;
}
reference_wrapper
ArgumentsUnder rule 1, arguments to bind
can be objects of type reference_wrap-per<Ty>
. In this case, the argument passed to the target object is passed by reference rather than by value.
Example 10.6. Rule 1 (funobjbind/rule1.cpp
)
#include <functional>
#include <iostream>
using std::tr1::bind; using std::tr1::ref;
using std::cout;
void modify(int& arg)
{ // add 1 to argument
++arg;
}
int main()
{ // demonstrate use of reference_wrapper with bind
int i = 0;
cout << i << '
';
// i passed by value; not modified
bind(modify, i)();
cout << i << '
';
// i passed by reference; modified
bind(modify, ref(i))();
cout << i << '
';
return 0;
}
In the first call to bind
, the argument i
is passed directly. Its value is copied into the callable object returned by bind
, and that copy is passed to modify
when the callable object is called. Because modify
is passed a copy of i
, the original value of i
is not changed.
In the second call to bind
, the argument i
is wrapped in a reference_-wrapper
object by the call to ref
. The callable object returned by bind
holds a reference to i
, and that reference is passed in the call to modify
. The value of i
is changed by the call to modify
.
bind
template <class Ty> struct is_placeholder {
static const int value;
};
template <class Ty> struct is_bind_expression {
static const bool value;
};
As mentioned earlier, bind
determines whether an argument of type Arg
is a placeholder by examining is_placeholder<Arg>::value
. If its value is zero, the argument is not a placeholder; if its value is nonzero the value indicates which argument the placeholder refers to. Similarly, is_bind_expression<Arg>::value
is true
if Arg
is a bind
expression.
These templates can be specialized for types defined in your code.[4] In particular, if you’re using another template library that binds arguments to callable types, you can pass that library’s objects and placeholders to bind
if you’ve provided specializations of is_placeholder
and is_bind_expression
for that library’s types. The call to bind
and to the object it returns will then follow rules 2 and 3.
For each of the following errors, write a simple test case containing the error, and try to compile it. In the error messages, look for the key words that relate to the error in the code.
1. Calling bind
with a placeholder argument that tries to use an argument that is past the implementation’s maximum allowed value.
2. Calling bind
with fewer or more arguments than the callable object takes. (You may have to call the returned object to get an error message.)
3. Calling an object returned by bind
with a literal value instead of an lvalue.
4. Calling bind
with a first argument that is not a callable object. (You may have to call the returned object to get an error message.)
Write a program that calls bind
, passing a pointer to the standard library function cosf
and the value 1.0f
, and calls the resulting callable object with no arguments. Show the result.
Write a program that calls bind
, passing a pointer to the standard library function cosf
and the placeholder _1
, and calls the resulting callable object with an argument that is a variable of type float
holding the value 1.0f
.
Write a program that calls bind
, passing a pointer to the standard library function cosf
and the placeholder _2
, and calls the resulting callable object with two arguments. The second argument should be a variable of type float
holding the value 1.0f
.
Write a program that defines a type named employee
with a public member function named ID
that takes no arguments and returns a value of type int
. The constructor for employee
should set the value that will be returned by ID
. Create a callable object whose function call operator returns true
for all employee
objects whose ID
is greater than 10. This takes two steps: Call bind
to bind the member function ID
to the employee object that will be passed to the function call operator (use _1
to refer to that object), and call bind
again to pass that result and the value 10
to the standard library class template less
. Create a TR1 array of employee
objects, and use the standard algorithm count_if
to count the number of employees whose ID
is greater than 10.
Using the employee
type from the previous example, write a program that sorts a standard library vector
object that holds employee
objects so that the contained objects are in order according to their ID
values.
3.17.76.175