I have a legacy C code base, which I am migrating to C++ in a piecemeal fashion. It includes an interpreter, so there is a need to wrap static functions and arguments for use by the interpreter. So a typical function for export to the interpreter may have the following signature:
static void do_strstr(struct value * p)
and be exposed to the interpreter like so:
using vptr = void (*) ();
template <typename Func>
constexpr vptr to_vptr(Func && func)
{ return reinterpret_cast<vptr>(func); }
struct function string_funs[] = {
...
{ C_FN3, X_A3, "SSI", to_vptr(do_strstr), "find" },
...
};
This has been proven to work. The drawback with the method so far is that the called function must allocate memory onto a temporary stack. An improvement would be where the called function just returns a string, for example. This function is then wrapped, where the wrapper does the memory magic behind the scenes. This allows functions to created in a more vanilla way.
Here is an implementation which concatenates two strings using my improved method:
static std::string do_concata(struct value* p)
{
std::string s1 = (p)->gString();
std::string s2 = (p+1)->gString();
return s1+s2;
}
I create a helper function:
static void do_concata_1(struct value* p)
{
wrapfunc(do_concata)(p);
}
where the somewhat generic wrapper is defined as:
std::function<void(struct value*)>
wrapfunc(std::function<std::string(struct value*)> func)
{
auto fn = [=](struct value* p) {
std::string s = func(p);
char* ret = alloc_tmp_mem(s.size()+1);
strcpy(ret, s.c_str());
p->sString(ret);
return;
};
return fn;
}
which is exposed to the interpreter as follows:
struct function string_funs[] = {
...
{ C_FN2, X_A2, "SS", to_vptr(do_concata_1), "concata" },
...
};
I am not satisfied with this solution, though, as it requires a helper function for each function I define. It would be better if I could eliminate do_concata_1
and write another function that wraps the wrapfunc
.
And this is where the problem is. If I write:
vptr to_vptr_1(std::function<void(struct value*)> func)
{
return to_vptr(wrapfunc(func));
}
then the compiler complains:
stringo.cc: In function ‘void (* to_vptr_1(std::function<void(value*)>))()’:
stringo.cc:373:30: error: could not convert ‘func’ from ‘std::function<void(value*)>’ to ‘std::function<std::__cxx11::basic_string<char>(value*)>’
return to_vptr(wrapfunc(func));
which is bizarre in my mind, because where did the std::__cxx11::basic_string<char>
come from? It should be void
, surely?
I'm at a loss to see what the fix should be. I am also a bit confused as to whether I should be passing copies of functions, references to functions, or the enigmatic &&
r-vale references.