Greetings,
I hope everyone is enjoying the Holiday Season :) !
I'm attempting to implement a function template [called 'generate_while ']
modelled somewhat on the STL's, 'generate' and 'generate_n' algorithms. Now,
'generate_while ', requires the use of temporary storage [mind the
line-wrap]:
template <class OutputIter_, class Generator_, class Predicate_>
OutputIter_ generate_while( OutputIter_ first_,
Generator_& gen_, Predicate_ pred_)
{
typename std::iterator_t raits<OutputIte r_>::value_type value_(gen_());
for ( ; pred_(value_); ++first_)
{
*first_ = value_; value_ = gen_();
}
return first_;
}
and here is how I've instantiated it:
typedef ostreambuf_iter ator<char> StreamIterOut;
...
generate_while( StreamIterOut(c out),
mandel,
MandelbrotGener ator::Done(mand el));
...
As you can see I've attempted to use the iterator's type traits to obtain
the type on which the template function will operate. This appears to be a
legitimate approach to take [I used the example from section 7.5.1 of
Josuttis' Standard C++ Library]. The code [full code appears below at
message end] compiles using the Borland 5.51 compiler, and executes
correctly.
However, attempting to compile the same code under GCC 3.3.1 resulted in the
following errors:
mandelbrot.cpp: In function `OutputIter_ generate_while( OutputIter_,
Generator_&, Predicate_) [with OutputIter_ =
std::ostreambuf _iterator<char,
std::char_trait s<char> >, Generator_ = MandelbrotGener ator, Predicate_ =
MandelbrotGener ator::Done]':
mandelbrot.cpp: 93: instantiated from here
mandelbrot.cpp: 30: error: instantiation of `value_' as type `void'
mandelbrot.cpp: 30: error: `value_' has incomplete type
mandelbrot.cpp: 30: error: storage size of `value_' isn't known
mandelbrot.cpp: 32: error: no match for call to
`(MandelbrotGen erator::Done) (
<typeprefixerro r>&)'
mandelbrot.cpp: 64: error: candidates are: bool
MandelbrotGener ator::Done::ope rator()(char) const
mandelbrot.cpp: 34: confused by earlier errors, bailing out
A further check using the Comeau 'tryitout' compiler web-page emits the
following:
"ComeauTest .c", line 22: error: incomplete type is not allowed
typename std::iterator_t raits<OutputIte r_>::value_type value_(gen_());
^
detected during instantiation of "OutputIter _
generate_while( OutputIter_, Generator_ &, Predicate_)
[with OutputIter_=std ::ostreambuf_it erator<char,
std::char_trait s<char>>, Generator_=Mand elbrotGenerator ,
Predicate_=Mand elbrotGenerator ::Done]"
Quite obviously the code is doing something 'non-standard', not to mention
'unacceptable', to these later, more Standard-conforming compilers. What I
would greatly appreciate [aside from a solution / fix of course ;) !] is an
explanation of what appears to be going wrong as it's not at all clear to
me.
Cheers,
Anthony Borla
#include <cstdlib>
#include <complex>
#include <functional>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <iostream>
using namespace std;
typedef complex<double> Complex;
typedef ostreambuf_iter ator<char> StreamIterOut;
/* ----------------------------- */
// STL 'lookalike' algorithm [based on STL's 'generate_n']
template <class OutputIter_, class Generator_, class Predicate_>
OutputIter_ generate_while( OutputIter_ first_, Generator_& gen_, Predicate_
pred_)
{
typename std::iterator_t raits<OutputIte r_>::value_type value_(gen_());
for ( ; pred_(value_); ++first_)
{
*first_ = value_; value_ = gen_();
}
return first_;
}
/* ----------------------------- */
class MandelbrotGener ator
{
public:
enum { EOS = -1 };
public:
MandelbrotGener ator(int height, int width);
bool done() const { return eos_; }
char next();
void reset();
void header(ostream& out) const;
operator bool() const { return !done(); }
char operator()() { return next(); }
public:
struct Done
{
public:
Done(Mandelbrot Generator& mref) : mref_(mref) { mref_.reset(); }
bool operator()(char ) const { return !mref_.done(); }
private:
MandelbrotGener ator& mref_;
};
private:
MandelbrotGener ator(const MandelbrotGener ator&);
MandelbrotGener ator& operator=(const MandelbrotGener ator&);
static int mandel(int n, const Complex& z, const Complex& c);
private:
int x_, y_, height_, width_;
bool eos_;
};
/* ----------------------------- */
int main(int argc, char* argv[])
{
ios_base::sync_ with_stdio(fals e);
if (argc != 2) { cerr << "Usage: " << argv[0] << " height"; return
EXIT_FAILURE; }
int n; if (!(istringstrea m(argv[1]) >> n) || n < 1) n = 100;
MandelbrotGener ator mandel(n, n);
mandel.header(c out);
generate_while( StreamIterOut(c out), mandel,
MandelbrotGener ator::Done(mand el));
return EXIT_SUCCESS;
}
/* ----------------------------- */
MandelbrotGener ator::Mandelbro tGenerator(int height, int width)
: x_(0), y_(0), height_(height) , width_(width), eos_(false)
{
}
/* ---------- */
char MandelbrotGener ator::next()
{
char byte = 0; int bitNumber = 0, limitMarker; bool output = false;
for ( ; y_ < height_; ++y_)
{
for ( ; x_ < width_; ++x_)
{
Complex z, c(2.0 * x_ / width_ - 1.5, 2.0 * y_ / height_ - 1.0);
limitMarker = mandel(50, z, c);
bitNumber += 1; if (bitNumber == 8) output = true;
byte = (byte << 1) | limitMarker;
if (x_ == width_ - 1 && bitNumber != 8)
{
byte = byte << (8 - width_ % 8); output = true;
}
if (output) { ++x_; return byte; }
}
x_ = 0;
}
eos_ = true ; return EOS;
}
/* ----------- */
void MandelbrotGener ator::reset()
{
x_ = 0; y_ = 0; eos_ = false;
}
/* ----------- */
void MandelbrotGener ator::header(os tream& out) const
{
out << "P4" << "\n" << width_ << " " << height_ << endl;
}
/* ----------- */
int MandelbrotGener ator::mandel(in t n, const Complex& z, const Complex& c)
{
if (real(z * conj(z)) > 4.0) return 0;
if (n == 0) return 1;
return MandelbrotGener ator::mandel(--n, z * z + c, c);
}