c - 在 C++11 中重构 C 函数输入输出和输入破坏参数
问题描述
我必须使用几个像往常一样具有输入、输入-输出和输出参数的遗留 C 函数,并且我想将它们包装在 C++ 函数中。
(double
为了简单起见,我在这里用作参数,但我认为这个问题对于涉及大量成员的参数也是有效的struct
。)
C 函数如下所示:
void Cfun(double* in_a, double* io_b, double* out_c, double* in_destr_d){}
在文档中,它说第一个参数a
是输入参数,b
是输入输出,c
是输出,并且d
是一个输入参数,返回时将包含未指定的(垃圾)值。(并且所有的指针都必须是非空的,并且只取一个元素,所以不涉及数组。)
在 C++ 中,很明显可以Cfun
通过以下方式进行重构而不损失:
double fun0(double a, double& b, double d){
double c;
Cfun(const_cast<double*>(&a), &b, &c, &d);
return c;
}
哪个应该有效,但也将涉及原始 C 版本中没有的副本。因此,鉴于我们对Cfun
(文档+我们知道我们在做什么)的了解,一个更好的版本可能是:
double fun1(double const& a, double& b, double& d){
double c;
Cfun(const_cast<double*>(&a), &b, &c, &d);
return c;
}
即,a
被提升为 const 引用,b
并d
被提升为引用并c
被提升为返回值。
这个函数可以这样使用:
double a = 1.1;
double b = 1.2;
double d = 1.3;
一世)
...
double c1 = fun1(1.1, b, d);
ii)
...
double c1 = fun1(a , b, d);
// b has useful information here
// d has garbage
那就是第二个和第三个参数必须是左值,这很好。
b
但是,参数和之间存在细微差别d
。虽然b
有用的信息d
基本上被破坏了,但在函数调用之后使用它的值无论如何都是错误的。
这种情况让我想起了 C++11 中的 r 值引用和移动。移动的 r 值参数最终处于未指定但可分配的状态。这让我认为 C 中的 input-to-garbage 参数可以或多或少地映射到 r 值引用。
换句话说,包装器可以这样写来传达 , 的值d
不仅会改变,而且会处于不可用状态。
double fun2(double const& a, double& b, double&& d){
double c;
Cfun(const_cast<double*>(&a), &b, &c, &d);
return c;
}
这听起来合理吗,我是否通过定义这个包装器而失去了一些东西?类似的情况是否在类似的情况下实施?这是否证明了内置类型的 r 值(如double
这里)?
d
我发现的一个小问题是语法会变得更加冗长,尽管从函数调用后的可用性的角度来看更加清晰。
据我现在所见,可能的语法更改为:
一世)
...
// double c = fun2(1.1, b, d); // now compile error, d is not a r-value
double c = fun2(1.1, b, std::move(d));
// obvious error to use the value of d, since it was (probably) moved. However "moving a POD??"
d = 2.; // assignment is ok
ii)
...
double c = fun2(1.1, b, 1.3); // good, I can pass a literal now, nothing to misuse
iii)
...
double c = fun2(1.1, b, double{d}); // not clear, reaction "this seems a redudant cast"
iv)
...
double c = fun2(1.1, b, copy(d)); // verbose, but "d should be fine because it was copied"
在哪里template<class T> T copy(T&& t){return t;}
总之,比?fun2
更好的包装器?Cfun
fun1
如果double
在上面的所有示例中都替换为具有 29 个成员变量(并且不想复制它们)的结构怎么办?
解决方案
我的第一反应是 C 接口似乎采用指向任意(从接口中未知...)长度数组的指针,而当您创建 C++ 接口时,您似乎假设(知道??)所有参数实际上只是标量? 当然 - 如果确实如此,那就太好了。
如果所有参数确实是标量的概念是正确的,我会这样做:
double fun(double a, double& b, double d);
并完成。
推荐阅读
- apache-kafka - 消费者获取数据返回 OFFSET_OUT_OF_RANGE
- javascript - 在正则表达式中使用积极的前瞻性来忽略最后是否相等
- css - 如何设置填充,以便在清理错误表单后获得正常样式
- css - 无法弄清楚如何让地铁图标字体或天气图标字体工作或如何保存 SVG
- asp.net - 使用 Directory.GetFiles() 读取项目文件夹内的文件夹
- cakephp - CakePHP4 未显示或记录致命错误
- javascript - 使用 JavaScript 生成随机树
- kubernetes - 服务 - pod 流量 - 选择器
- c# - 如何从 JSON 中删除不需要的字符串属性
- ios - 如何防止iOS上的Web-Audio在访问麦克风时切换到单声道?