Reputation: 12347
I'm deriving a class from a base class outside my control. The class will get created by a factory function pointer I pass in (in a part of the code I also don't control).
In my derived class, I need to pass an additional constructor argument to the factory function.
My first stab was to try to adapt the factory function via a lambda, but that cannot capture the additional argument. Other answers explained why that doesn't work. Next I've tried to augment that with std::function
which other answers have led me to believe would work, but I can't figure out the right syntax and have found the examples to be incomprehensible (and not sure I really understand what that is even doing).
What am I doing wrong here? Is there a better way to solve this?
Demonstration code:
#include <functional>
#include <string>
// I have no control over this
struct Base {
Base(int i) {}
};
void UseObject(Base *(*factory)(int i)) {
Base *instance = factory(5);
// Save created instance
}
// I control the rest
struct Derived : public Base {
Derived(const char *s, int i) : Base(i) { /* Store s for later use */ }
static Base *Factory(const char *s, int i) { return new Derived(s, i); }
};
void AddObject(const char *name)
{
// First stab
// UseObject([name] (int i) { return Derived::Factory(name, i); });
// Second stab
std::function<Base *(int i)> foo { [name] (int i) { return Derived::Factory(name, i); } };
UseObject(foo);
}
int main(int ac, char **av)
{
AddObject("some_name");
AddObject("another_name");
return 0;
}
The error I get from g++ (7.4.0) is:
tfunc.cpp: In function ‘void AddObject(const char*)’:
tfunc.cpp:28:18: error: cannot convert ‘std::function<Base*(int)>’ to ‘Base* (*)(int)’ for argument ‘1’ to ‘void UseObject(Base* (*)(int))’
UseObject(foo);
Upvotes: 0
Views: 39
Reputation: 217283
UseObject
doesn't allow non capturing lambda or std::function
or regular class functor. The only callable it accepts is function pointer (non capturing lambda can convert to).
So you might do:
UseObject([](int i) { return Derived::Factory("some_name", i); });
but not
auto name = "some_name";
UseObject([name] (int i) { return Derived::Factory(name, i); });
Possible (limited) workaround is to use global variable to store state. (So cannot be used concurrently).
void AddObject(const char *name)
{
// global usage as UseObject only accepts pointer function
static const char* instance = nullptr;
instance = name;
UseObject(+[](int i) { return Derived::Factory(instance, i); });
}
Upvotes: 1