【问题标题】:Compiler error wrapping an interpretable function包装可解释函数的编译器错误
【发布时间】:2018-04-21 14:00:44
【问题描述】:

我有一个遗留的 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&lt;char&gt; 是从哪里来的?应该是void,确定吗?

我不知道应该修复什么。对于我应该传递函数的副本、函数的引用还是神秘的 &amp;&amp; r-vale 引用,我也有点困惑。

【问题讨论】:

  • 这里唯一现实的解决办法是用火烧掉整个东西,然后使用现代 C++ 以类型安全的形式从头开始重新实现它。
  • @Sam。代码库很繁琐,这是真的,但我宁愿重构也不愿重写。还要记住,因为函数是在解释器中使用的,所以无论如何都必须有一种机制来包装和解包函数。整个 alloc_tmp_mem() 和 strcpy() 是不幸的,但不是灾难。至少在我提议的重构中,在代码中创建了一个关键点。这将允许我在以后的某个时间点改进代码。

标签: c++


【解决方案1】:

to_vptr_1() 中,func 被建立为返回void 的函数。但是func 被传递给wrapfunc(),它需要一个返回std::string 的函数。编译器无法将funcstd::function&lt;void(struct value*)&gt; 转换为std::function&lt;std::string(struct value*)&gt;,因此会发出错误消息。

std::function 到原始函数指针的reinterpret_cast 不起作用。 This question 对此主题进行了一些很好的讨论,this one 有一个解决方案,也许可以针对这种情况进行重新设计。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多