我有一个遗留的C代码库,我将以零散的方式迁移到C ++。它包括一个解释器,因此需要包装静态函数和参数以供解释器使用。因此,导出到解释器的典型功能可能具有以下签名:
static void do_strstr(struct value * p)
并像这样接触翻译:
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" },
...
};
这已被证明有效。到目前为止,该方法的缺点是被调用的函数必须将内存分配到临时堆栈上。例如,改进的地方是被调用的函数只返回一个字符串。然后包装此函数,其中包装器在幕后完成记忆魔术。这允许以更香草的方式创建函数。
这是一个使用我的改进方法连接两个字符串的实现:
static std::string do_concata(struct value* p)
{
std::string s1 = (p)->gString();
std::string s2 = (p+1)->gString();
return s1+s2;
}
我创建了一个辅助函数:
static void do_concata_1(struct value* p)
{
wrapfunc(do_concata)(p);
}
其中有点通用的包装器定义为:
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;
}
如下所示接触解释器:
struct function string_funs[] = {
...
{ C_FN2, X_A2, "SS", to_vptr(do_concata_1), "concata" },
...
};
我对此解决方案不满意,因为它需要为我定义的每个函数提供辅助函数。如果我可以消除do_concata_1
并编写另一个包裹wrapfunc
的函数,那会更好。
这就是问题所在。如果我写:
vptr to_vptr_1(std::function<void(struct value*)> func)
{
return to_vptr(wrapfunc(func));
}
然后编译器抱怨:
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));
这在我看来很奇怪,因为std::__cxx11::basic_string<char>
来自哪里?肯定应该是void
?
我不知道该修复应该是什么。关于我是否应该传递函数副本,函数引用或神秘的&&
r-vale引用,我也有点困惑。
答案 0 :(得分:0)
在func
中,void
被建立为返回func
的函数。但是wrapfunc()
传递给std::string
,它需要一个返回func
的函数。编译器无法将std::function<void(struct value*)>
从std::function<std::string(struct value*)>
转换为reinterpret_cast
,因此会发出错误消息。
std::function
到原始函数指针的{{1}}无法正常工作。 This question对此主题进行了一些很好的讨论,this one有一个解决方案可能会针对这种情况进行重新设计。