I'm new to std::generate and have attempted to structure a program which uses it to initialize vectors. However it's behaving differently to my expectations.
I have an abstract base class:
template <typename G>
class RandomAllele {
public:
RandomAllele() { /* empty */ }
virtual ~RandomAllele() { /* empty */ }
virtual G operator()() const = 0;
};
Which is extended by (for example):
class RandomInt : public RandomAllele<int> {
public:
RandomInt(int max) : max_(max) {}
int operator()() const { return rand() % max_; }
private:
int max_;
};
I pass an instance of my inheriting class to a factory class by pointer, and then use it as the third argument for std::generate:
template<typename G, typename F>
class IndividualFactory {
public:
IndividualFactory(int length, const RandomAllele<G> *random_allele)
: length_(length), random_allele_(random_allele) { /* empty */ }
individual_type *generate_random() const {
std::vector<G> *chromosome = new std::vector<G>(length_);
std::generate(chromosome->begin(), chromosome->end(), *random_allele_); */
return new individual_type(chromosome);
}
private:
int length_;
RandomAllele<G> *random_allele_;
};
Now I get an error saying that RandomAllele cannot be instantiated because it's an abstract class. Why does generate need to instantiate it when the pointer already exists? And why is it trying to use the base class instead of the inheriting class RandomInt?
This works fine if I replace std::generate with:
for(auto iter = chromosome->begin(); iter != chromosome->end(); ++iter)
*iter = (*random_allele_)();
But I still wish to understand why it behaves strangely, and I'd prefer to use generate if there is a way to do this.
Thanks for your time,
Rhys
As others have mentioned above, the
generate
andgenerate_n
functions take their generator objects by value, precluding you from directly using inheritance in this context.However, one trick you can do is to apply the Fundamental Theorem of Software Engineering:
Rather than directly passing in a polymorphic functor, instead pass in a wrapper functor that stores a pointer to this polymorphic functor and then forwards the call appropriately. For example:
If you then pass this object into
generate
, as seen here:Then everything will work as intended. The reason for this is that if you copy
IndirectFunctor<T>
by value, then you just shallow-copy the stored pointer, which will still point to theRandomAllele
you want to call. This avoids the slicing problem you were encountering because it never tries directly copying an object of typeRandomAllele
through a base class pointer. It always copies the wrapper object, which never tries to duplicateRandomAllele
.Hope this helps!