I have a base class with a vector of pointers, and I think to slide the vector outside this class, I wrote the for_each() method:
class model {
static std::vector<model*> models;
...
public:
template <class C>
static void for_each(C *c,void (C::*f)(model *))
{
for (std::vector<model*>::iterator it=models.begin(); it!=models.end(); it) {
c->f(*it);
}
...
}
I tryed to use for_each() in a member function:
void v_context::build_cmd()
{
...
auto f1=[&](model* m)->void{commandBuffers.push_back(*(m->build_secondary_buffers(inheritanceInfo, pipelines.gltf)));};
model::for_each<VulkanExample,void (VulkanExample::*)(model*)>(this,f1);
...
}
The compiler (gcc version 10.2.1 20210110 (Debian 10.2.1-6)), rightly returns the error:
error: cannot convert ‘v_context::build_cmd()::<lambda(model*)>’ to ‘void (v_context::)(model)’
note: initializing argument 2 of ‘static void model::for_each(C*, void (C::)(model)) [with C=v_context]’
Is it possible? Does correct syntax template exist?
CodePudding user response:
The simplest is probably to make it even more generic:
class model {
static std::vector<model *> models;
public:
template <class Func>
static void for_each(Func&& func) { // no instance needed
for (auto ptr : models) { // simplified loop
func(ptr);
}
}
};
Then just capture [this]
in the lambdas you use it with:
void VulkanExample::build_cmd() {
auto f1 = [this](model *m) {
// ...
};
model::for_each(f1);
}
CodePudding user response:
You could use std::invoke
to implement this logic. A class and a member function pointer this would require swapping the parameters, but otherwise this would allow you to pass any number of additional parameters before the model*
parameter:
class model
{
...
template <class F, class...Args>
static void for_each(F&& f, Args&&...args)
{
for (auto p : models)
{
std::invoke(f, args..., p);
}
}
...
};
Example usages:
struct Foo
{
void Bar(model*) {}
};
...
Foo foo;
model::for_each(&Foo::Bar, foo);
model::for_each([&](model* m)->void{commandBuffers.push_back(*(m->build_secondary_buffers(inheritanceInfo, pipelines.gltf)));});