I am relatively new to c++ and this is my very first post, so be gentle ;-)
I understand how to pass function pointers or function objects, like many stl functions require. It is unclear to me how to use this in combination with inheritance.
Specifically I would like to call a stl function with several functors that inherit from a base functor. I have not found any relevant remarks or best practices on this topic. Here a simplified code snippet:
struct generator{
virtual int operator()() = 0;
virtual ~generator(){};
};
struct A : public generator{
int operator()();
};
struct B : public generator{
int operator()();
};
int main()
{
auto v = std::vector<std::array<int, 500>>(2);
std::array<std::shared_ptr<generator>, 2> functors = {{std::make_shared<A>(),
std::make_shared<B>()}};
for (size_t i = 0; i < functors.size(); ++i)
std::generate(std::begin(v[i]), std::end(v[i]),
*(functors[i]));
return 0;
}
Compiling this gives:
clang++ -std=c++11 -g -Wall -Wextra test_stackoverflow.cpp
test_stackoverflow.cpp:25:5: error: no matching function for call to 'generate'
std::generate(std::begin(v[i]), std::end(v[i]),*(functors[i]));
^~~~~~~~~~~~~
/usr/lib/gcc/i686-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_algo.h:5003:5: note: candidate template ignored: substitution
failure [with _ForwardIterator = int *, _Generator = generator]: parameter type 'generator' is an abstract class
generate(_ForwardIterator __first, _ForwardIterator __last,
Yes the type of *(functors[i]) is generator. Which will not allow for dynamic access to A::operator() and B::operator(). I understand how to (rudamentally) solve this. e.g.
std::generate(std::begin(v[i]), std::end(v[i],
[&]{ return functors[i]->operator()(); };
However this seems rather obfuscated and I'm looking for a clearer way to achieve my goals.
How does one usually pass such dynamic functors. Or if this is frowned upon, what is the best alternative?
Any help or suggestions are most welcome.
The problem, as you may already know, is that std::generate
takes the generator by value. To pass a polymorphic object, you must pass by reference.
And there is a solution for exactly this kind of problem in c++11 (besides the lambda option, which is still more elegant than what we had before c++11, I believe). The solution is std::ref. It returns a reference wrapper that can be passed by value.
This should work for you:
std::generate(std::begin(v[i]), std::end(v[i]),
std::ref(*(functors[i])));
The reason why you can pass reference wrappers as a functor, is that they implement the operator()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With