"mlimber" wrote:
>
> A generator approach: Using functional composition [let's call ours
> my_compose(f,g) = f(g())], whose implementation is relatively
> straightforward and similar to the common extension to the STL (e.g.,
> http://www.sgi.com/tech/stl/unary_compose.html), one can make this
> clearer on first reading:
>
> std::generate( begin, end, my_compose( Square, phase ) );
I like this approach; the idea of function composition is appealing. The
problem is handling state. The waveform function object is stateless, a true
function. However, the phase accumulator has state, specifically the value
of its phase. Say I have the following:
void Oscillator:

rocess(float *begin, float *end)
{
// Assumes a phase member variable.
std::generate(begin, end, my_compose(Square(), phase);
}
Each time Process is called the phase needs to pick up from where it left
off with the previous call. However, 'phase' is passed in by value, so the
phase accumulator that's actually getting advanced by generate is a copy of
the original. The end result is that each time Process is called, phase
starts at the same place.
I see a couple of ways around this. Design the phase accumulator so that it
takes a pointer to the actual phase variable:
// Inside the Oscillator class..
// Member variable.
float phase;
//...
void Oscillator:

rocess(float *begin, float *end)
{
std::generate(begin, end, my_compose(Square(),
PhaseAccumulator(&phase));
}
This ensures that the phase value that's getting incremented persists
between calls since the PhaseAccumulator is incrementing the pointer
variable.
I suppose this solution is ok.
Another approach is to somehow update the phase accumulator after generate
has done its job:
void Oscillator:

rocess(float *begin, float *end)
{
MyCompose<Square, PhaseAccumulator> mc(Square(), phase);
std::generate(begin, end, mc);
// Assumes our custom compose template exposes the generator function
object.
phase = mc.generator;
}
This works as well. Another way is to explicitely tell the generate function
to treat the phase accumulator object as a reference, but then I'm pretty
sure I'd lose inlining in that case. Things would start to look ugly at that
point anyway.
Also, we can forego the convenience of using generate and simply write the
loop ourselves using the same member variables:
void Oscillator:

rocess(float *first, float *last)
{
while(first != last)
{
// Assumes phase and wave are member variables.
*first = wave(phase());
first++;
}
}