A
Anthony Borla
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_traits<OutputIter_>::value_type value_(gen_());
for ( ; pred_(value_); ++first_)
{
*first_ = value_; value_ = gen_();
}
return first_;
}
and here is how I've instantiated it:
typedef ostreambuf_iterator<char> StreamIterOut;
...
generate_while(StreamIterOut(cout),
mandel,
MandelbrotGenerator:
one(mandel));
...
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:
streambuf_iterator<char,
std::char_traits<char> >, Generator_ = MandelbrotGenerator, Predicate_ =
MandelbrotGenerator:
one]':
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
`(MandelbrotGenerator:
one) (
<typeprefixerror>&)'
mandelbrot.cpp:64: error: candidates are: bool
MandelbrotGenerator:
one:
perator()(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_traits<OutputIter_>::value_type value_(gen_());
^
detected during instantiation of "OutputIter_
generate_while(OutputIter_, Generator_ &, Predicate_)
[with OutputIter_=std:
streambuf_iterator<char,
std::char_traits<char>>, Generator_=MandelbrotGenerator,
Predicate_=MandelbrotGenerator:
one]"
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_iterator<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_traits<OutputIter_>::value_type value_(gen_());
for ( ; pred_(value_); ++first_)
{
*first_ = value_; value_ = gen_();
}
return first_;
}
/* ----------------------------- */
class MandelbrotGenerator
{
public:
enum { EOS = -1 };
public:
MandelbrotGenerator(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(MandelbrotGenerator& mref) : mref_(mref) { mref_.reset(); }
bool operator()(char) const { return !mref_.done(); }
private:
MandelbrotGenerator& mref_;
};
private:
MandelbrotGenerator(const MandelbrotGenerator&);
MandelbrotGenerator& operator=(const MandelbrotGenerator&);
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(false);
if (argc != 2) { cerr << "Usage: " << argv[0] << " height"; return
EXIT_FAILURE; }
int n; if (!(istringstream(argv[1]) >> n) || n < 1) n = 100;
MandelbrotGenerator mandel(n, n);
mandel.header(cout);
generate_while(StreamIterOut(cout), mandel,
MandelbrotGenerator:
one(mandel));
return EXIT_SUCCESS;
}
/* ----------------------------- */
MandelbrotGenerator::MandelbrotGenerator(int height, int width)
: x_(0), y_(0), height_(height), width_(width), eos_(false)
{
}
/* ---------- */
char MandelbrotGenerator::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 MandelbrotGenerator::reset()
{
x_ = 0; y_ = 0; eos_ = false;
}
/* ----------- */
void MandelbrotGenerator::header(ostream& out) const
{
out << "P4" << "\n" << width_ << " " << height_ << endl;
}
/* ----------- */
int MandelbrotGenerator::mandel(int n, const Complex& z, const Complex& c)
{
if (real(z * conj(z)) > 4.0) return 0;
if (n == 0) return 1;
return MandelbrotGenerator::mandel(--n, z * z + c, c);
}
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_traits<OutputIter_>::value_type value_(gen_());
for ( ; pred_(value_); ++first_)
{
*first_ = value_; value_ = gen_();
}
return first_;
}
and here is how I've instantiated it:
typedef ostreambuf_iterator<char> StreamIterOut;
...
generate_while(StreamIterOut(cout),
mandel,
MandelbrotGenerator:
...
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:
std::char_traits<char> >, Generator_ = MandelbrotGenerator, Predicate_ =
MandelbrotGenerator:
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
`(MandelbrotGenerator:
<typeprefixerror>&)'
mandelbrot.cpp:64: error: candidates are: bool
MandelbrotGenerator:
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_traits<OutputIter_>::value_type value_(gen_());
^
detected during instantiation of "OutputIter_
generate_while(OutputIter_, Generator_ &, Predicate_)
[with OutputIter_=std:
std::char_traits<char>>, Generator_=MandelbrotGenerator,
Predicate_=MandelbrotGenerator:
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
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_iterator<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_traits<OutputIter_>::value_type value_(gen_());
for ( ; pred_(value_); ++first_)
{
*first_ = value_; value_ = gen_();
}
return first_;
}
/* ----------------------------- */
class MandelbrotGenerator
{
public:
enum { EOS = -1 };
public:
MandelbrotGenerator(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(MandelbrotGenerator& mref) : mref_(mref) { mref_.reset(); }
bool operator()(char) const { return !mref_.done(); }
private:
MandelbrotGenerator& mref_;
};
private:
MandelbrotGenerator(const MandelbrotGenerator&);
MandelbrotGenerator& operator=(const MandelbrotGenerator&);
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(false);
if (argc != 2) { cerr << "Usage: " << argv[0] << " height"; return
EXIT_FAILURE; }
int n; if (!(istringstream(argv[1]) >> n) || n < 1) n = 100;
MandelbrotGenerator mandel(n, n);
mandel.header(cout);
generate_while(StreamIterOut(cout), mandel,
MandelbrotGenerator:
return EXIT_SUCCESS;
}
/* ----------------------------- */
MandelbrotGenerator::MandelbrotGenerator(int height, int width)
: x_(0), y_(0), height_(height), width_(width), eos_(false)
{
}
/* ---------- */
char MandelbrotGenerator::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 MandelbrotGenerator::reset()
{
x_ = 0; y_ = 0; eos_ = false;
}
/* ----------- */
void MandelbrotGenerator::header(ostream& out) const
{
out << "P4" << "\n" << width_ << " " << height_ << endl;
}
/* ----------- */
int MandelbrotGenerator::mandel(int n, const Complex& z, const Complex& c)
{
if (real(z * conj(z)) > 4.0) return 0;
if (n == 0) return 1;
return MandelbrotGenerator::mandel(--n, z * z + c, c);
}