Consider how to write a program that converts strings representing floating-point numbers to their actual numeric values. To get things started, here’s a generator that creates the strings:.
//: C06:NumStringGen.h
// A random number generator that produces
// strings representing floating-point numbers
#ifndef NUMSTRINGGEN_H
#define NUMSTRINGGEN_H
#include
#include
#include
class NumStringGen {
const int sz; // Number of digits to make
public:
NumStringGen(int ssz = 5) : sz(ssz) {
std::srand(std::time(0));
}
std::string operator()() {
static char n[] = "0123456789";
const int nsz = sizeof n / sizeof *n;
std::string r(sz, ' ');
for(int i = 0; i < sz; i++)
if(i == sz/2)
r[i] = '.'; // Insert a decimal point
else
r[i] = n[std::rand() % nsz];
return r;
}
};
#endif // NUMSTRINGGEN_H ///:~
You tell it how big the strings should be when you create the NumStringGen object. The random number generator selects digits, and a decimal point is placed in the middle.
The following program uses NumStringGen to fill a vector
//: C06:MemFun3.cpp
// Using mem_fun()
#include
#include
#include
#include
#include
#include
#include "NumStringGen.h"
using namespace std;
int main() {
const int sz = 9;
vector
// Fill it with random number strings:
generate(vs.begin(), vs.end(), NumStringGen());
copy(vs.begin(), vs.end(),
ostream_iterator
cout << endl;
const char* vcp[sz];
transform(vs.begin(), vs.end(), vcp,
mem_fun_ref(&string::c_str));
vector
transform(vcp, vcp + sz, back_inserter(vd),
std::atof);
copy(vd.begin(), vd.end(),
ostream_iterator
cout << endl;
} ///:~
This program does two transformations: one to convert strings to C-style strings (arrays of characters), and one to convert the C-style strings to numbers via atof( ). It would be nice to combine these two operations into one. After all, we can compose functions in mathematics, so why not C++?.
The obvious approach takes the two functions as arguments and applies them in the proper order:
//: C06:ComposeTry.cpp
// A first attempt at implementing function composition
#include
#include
#include
#include
#include
using namespace std;
template
class unary_composer {
F1 f1;
F2 f2;
public:
unary_composer(F1 fone, F2 ftwo) : f1(fone), f2(ftwo) {}
R operator()(E x) {
return f1(f2(x));
}
};
template
unary_composer
return unary_composer
}
int main()
{
double x =
compose
mem_fun_ref(&string::c_str))("12.34");
assert(x == 12.34);
} ///:~
The unary_composer object in this example stores the function pointers atof and string::c_str such that the latter function is applied first when its operator( ) is called. The compose( ) function adapter is a convenience, so we don’t have to supply all four template arguments explicitly—F1 and F2 are deduced from the call.
It would be much better, of course, if we didn’t have to supply any template arguments at all. This is achieved by adhering to the convention for type definitions for adaptable function objects; in other words, we will assume that the functions to be composed are adaptable. This requires that we use ptr_fun( ) for atof( ). For maximum flexibility, we also make unary_composer adaptable in case it gets passed to a function adapter. The following program does so and easily solves the original problem.
//: C06:ComposeFinal.cpp
// An adaptable composer
#include
#include
#include
#include
#include
#include
#include
#include
#include "NumStringGen.h"
using namespace std;
template
class unary_composer