我必须使用几个传统的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;
i)
...
double c1 = fun1(1.1, b, d);
ii)
...
double c1 = fun1(a , b, d);
// b has useful information here
// d has garbage
第二个和第三个参数必须是l值,这很好。
但是,参数b
和d
之间存在细微的差别。尽管b
具有有用的信息,d
实际上已被销毁,并且在函数调用之后使用其值在任何情况下都是错误的。
这种情况让我想起了r值参考,并在C ++ 11中有所发展。 移动的r值参数最终处于未指定但可分配的状态。 这使我认为C语言中的垃圾输入参数可以或多或少地映射到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
的可用性来看,语法也会变得更加冗长。
据我所知,可能的语法更改为:
i)
...
// 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个成员变量的结构替换(并且不想复制它们)怎么办?
答案 0 :(得分:2)
我的第一个反应是C接口似乎采用了指向任意(长度未知的接口)长度数组的指针,而当您创建C ++接口时,您似乎假设(知道吗?)所有参数都会真正只是标量?当然-如果确实是这样,那一切都很好。
我认为所有参数确实都是标量的概念是正确的,
double fun(double a, double& b, double d);
并完成。