The function wrapper lets you rewrite the program so that it uses just one instantiation of use_f()
instead of five. Note that the function pointers, function objects, and lambda expressions in Listing 18.7 share a common behavior—each takes one type double
argument and each returns a type double
value. We can say that each has the same call signature, which is described by the return type followed by a comma-separated list of parameter types enclosed in a pair of parentheses. Thus, these six examples all have double(double)
as the call signature.
The function
template, declared in the functional
header file, specifies an object in terms of a call signature, and it can be used to wrap a function pointer, function object, or lambda expression having the same call signature. For example, the following declaration creates a function
object fdci
that takes a char
and an int
argument and returns type double
:
std::function<double(char, int)> fdci;
You can then assign to fdci
any function pointer, function object, or lambda expression that takes type char
and int
arguments and returns type double
.
The various callable arguments in Listing 18.7 all have the same call signature – double(double)
. So to fix Listing 18.7 and reduce the number of instantiations, we can use function<double(double)>
to create six wrappers for the six functions, functors, and lambdas. Then all six calls to use_f()
can be made with the same type (function<double(double)>
) for F
, resulting in just one instantiation. Listing 18.8 shows the result.
//wrapped.cpp -- using a function wrapper as an argument
#include "somedefs.h"
#include <iostream>
#include <functional>
double dub(double x) {return 2.0*x;}
double square(double x) {return x*x;}
int main()
{
using std::cout;
using std::endl;
using std::function;
double y = 1.21;
function<double(double)> ef1 = dub;
function<double(double)> ef2 = square;
function<double(double)> ef3 = Fq(10.0);
function<double(double)> ef4 = Fp(10.0);
function<double(double)> ef5 = [](double u) {return u*u;};
function<double(double)> ef6 = [](double u) {return u+u/2.0;};
cout << "Function pointer dub:
";
cout << " " << use_f(y, ef1) << endl;
cout << "Function pointer square:
";
cout << " " << use_f(y, ef2) << endl;
cout << "Function object Fp:
";
cout << " " << use_f(y, ef3) << endl;
cout << "Function object Fq:
";
cout << " " << use_f(y, ef4) << endl;
cout << "Lambda expression 1:
";
cout << " " << use_f(y, ef5) << endl;
cout << "Lambda expression 2:
";
cout << " " << use_f(y,ef6) << endl;
return 0;
}
Here is a sample output:
Function pointer dub:
use_f count = 1, &count = 0x404020
2.42
Function pointer sqrt:
use_f count = 2, &count = 0x404020
1.1
Function object Fp:
use_f count = 3, &count = 0x404020
11.21
Function object Fq:
use_f count = 4, &count = 0x404020
12.1
Lambda expression 1:
use_f count = 5, &count = 0x404020
1.4641
Lambda expression 2:
use_f count = 6, &count = 0x404020
1.815
As you can see from the output, there is just one address for count
, and the value of count
shows use_f()
has been called six times. So we now have just one instantiation invoked six times, reducing the size of the executable code.
3.147.72.74