Consider the following code:
#include <functional>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <time.h>
struct Foo {
Foo(int x) : x(x) {}
void func1() const { printf("Foo::func1 x=%d\n", x); }
void func2() const { printf("Foo::func2 x=%d\n", x); }
int x;
char junk[64];
};
struct Bar {
Bar(int x) : x(x) {}
void func3() const { printf("Bar::func3 x=%d\n", x); }
int x;
char junk[64];
};
void loop(std::function<void()>& g) {
for (int i=0; i<10; ++i) {
switch (rand()%3) {
case 0:
{
Foo foo(3);
g = std::bind(&Foo::func1, foo);
break;
}
case 1:
{
Foo foo(4);
g = std::bind(&Foo::func2, foo);
break;
}
case 2:
{
Bar bar(5);
g = std::bind(&Bar::func3, bar);
break;
}
default: break;
}
}
}
int main() {
srand(time(NULL));
std::function<void()> g;
loop(g);
g();
return 0;
}
This code will execute exactly one of Foo::func1()
, Foo::func2()
, or Bar::func3()
, using a copied instance of an object (that has fallen out of scope).
What I'd like to change with this code is to remove the dynamic allocation inside loop()
. To this end, I tried making a wrapper around std::function
, like so:
template <typename _Signature> class my_function;
template <typename R, typename... Args>
class my_function<R(Args...)> {
public:
template<typename T, typename FUNC>
void bind(FUNC&& func, const T& t) {
static_assert(sizeof(t) <= sizeof(obj_buffer), "insufficient obj_buffer size");
static_assert(std::is_trivially_destructible<T>::value, "memory leak");
auto p = new(obj_buffer) T(t); // placement new
auto ref = std::ref(*p);
f = std::bind(func, ref /* how do I forward variable # of placeholders here??? */);
}
R operator()(Args&& ...args) const { return f(std::forward<Args>(args)...); }
private:
char obj_buffer[1024];
std::function<R(Args...)> f;
};
I then changed the declaration of g
from std::function<void()>
to my_function<void()>
and replaced g = std::bind(x,y)
statements with g.bind(x,y)
ones inside loop()
. The code compiles and works as expected.
I have 2 separate questions:
Does the standard guarantee that we avoid dynamic memory allocation here? User Jarod42 told me that it does in a very similar setting using an anonymous lambda, but I'm not sure if the same holds here with
std::bind
.How do I instantiate
f
inside mybind()
function when I have a nonempty template parameter pack argumentArgs
? My code as is won't compile for nonemptyArgs
.