I am creating wrapper functions, that modify existing functions (targets). The targets are determined at runtime as pointers without type information (void*). Each of them has different parameters and return type. The wrapped functions are called from external code, so they have to match the signature of the target.
The basic scheme is like this:
bool wrap(void* f, void** t)
{
*t = magic(); // target determined at runtime as void*
return true;
}
// define new wrapping function and storage for target
int(*foo_target)(int);
int foo(int data)
{
return foo_target(data) + 10;
}
auto res = wrap(reinterpret_cast<void*>(&foo), reinterpret_cast<void**>(&foo_target));
The wrap function is a placeholder, that does all the heavy lifting. For each target I define a wrapper function (foo) and a variable to store the function pointer to the target function with the correct type (foo_target).
This works, but requires ugly type casts and I have to keep the signatures of foo_target and foo in sync manually. What I would like to have is something like this:
template <class F>
struct wrap
{
F* target;
wrap(F&& f)
{
target = reinterpret_cast<F*>(magic());
}
};
static auto foo = wrap(
[](int data) -> int // <- signature of the wrapper and target function
{
return foo.target(data) + 10; // ERROR
// return 10; // WORKS
});
}
The single type cast required is hidden in the wrap function, and the signature of the target function is in a single place. Of course, this does not work because foo cannot be used in the lambda like that.
If I use a common base class, I can make this solution work. However, in this case I need a type cast in every wrapper function and have to define the function signature twice.
struct wrap_base
{
void* target;
};
template <class F>
struct wrap : wrap_base
{
wrap(F&& f)
{
target = magic();
}
};
static wrap_base foo = wrap(
[](int data) -> int // <- signature of the wrapper and target function
{
using func = int(int); // <- repeated here
return reinterpret_cast<func*>(foo.target)(data) + 10;
});
Edit The target functions may have different calling conventions. This probably means that I cannot use (non-capturing) lambdas, although I have not had any issues so far.
It seems you want a recursive-lambda. One way is a Y-combinator, i.e adding
Selfparameter:Demo