假设我有一个看起来像这样的C ++函数:
double myfunction(double a, double b) {
// do something
}
然后我会这样称呼:
double a = 1.0;
double b = 2.0;
double good_r = myfunction(a, b);
double bad_r = myfunction(b, a); // compiles fine
我想确保a
和b
永远不会以错误的顺序提供。
在C ++中确保这一点的最佳方法是什么?
其他语言允许使用命名参数,如下所示:
double good_r = myfunction(a=a, b=b);
double bad_r = myfunction(a=b, b=a); // mistake immediately obvious
double bad_r = myfunction(b=b, a=a); // compiles fine
或许也可以使用类型来解决问题,即
double my_type_safe_function(a_type a, b_type b) {
// do something
}
a_type a = 1.0;
b_type b = 2.0;
double good_r = myfunction(a, b);
double bad_r = myfunction(b, a); // compilation error
编辑:有几个人问错了订单我的意思。"我的意思是,在实际代码中a
和b
具有一定的意义。例如,参数可能改为height
和width
。它们之间的区别对于返回正确结果的函数非常重要。但是,它们都是浮子,它们都具有相同的尺寸(即长度)。此外,没有明显的"为他们订购。编写函数声明的人可以假设(width, height)
,并且使用该函数的人可以假设(height, width)
。我想要一种方法来确保这不会发生错误。使用两个参数很容易对订单进行处理,但是在一个大型项目中,最多有6个参数会出现错误。
理想情况下,我希望检查在编译时完成,并且没有性能损失(即在一天结束时它们被视为普通的旧浮动或其他)。
答案 0 :(得分:3)
这个怎么样:
struct typeAB {float a; float b; };
double myfunction(typeAB p) {
// do something
return p.a - p.b;
}
int main()
{
typeAB param;
param.a = 1.0;
param.b = 2.0;
float result = myfunction(param);
return 0;
}
当然,您在分配参数时仍然会陷入困境,但这种风险很难避免:)
答案 1 :(得分:2)
一个变体是每个" new"键入,然后使用宏使它们在优化的构建中消失。
沿着这些方向的东西(仅经过轻微测试,因此可能会有所不同):
#define SAFE 0
#if SAFE
#define NEWTYPE(name, type) \
struct name { \
type x; \
explicit name(type x_) : x(x_) {}\
operator type() const { return x; }\
}
#else
#define NEWTYPE(name, type) typedef type name
#endif
NEWTYPE(Width, double);
NEWTYPE(Height, double);
double area(Width w, Height h)
{
return w * h;
}
int main()
{
cout << area(Width(10), Height(20)) << endl;
// This line says 'Could not convert from Height to Width' in g++ if SAFE is on.
cout << area(Height(10), Width(20)) << endl;
}
答案 2 :(得分:1)
我认为您已经使用类型提供了最简单的解决方案。
一种替代方法可能是使用构建器类和方法链接。 像:
class MyfunctionBuilder {
MyFunctionBuilder & paramA(double value);
MyFunctionBuilder & paramB(double value);
double execute();
(...)
}
您可以这样使用:
double good_r = MyFunctionBuilder().paramA(a).paramB(b).execute();
但这需要编写很多额外的代码!
答案 3 :(得分:0)
实际上“错误的订单”是什么?在你的这个例子中
double myfunction(double a, double b) {
// do something
}
double a = 1.0;
double b = 2.0;
double good_r = myfunction(a, b);
double bad_r = myfunction(b, a);
你真的想知道这个是否正确的顺序?如果变量被命名为“quapr”和“moo”而不是“a”和“b”怎么办?那么仅仅通过查看它们就不可能猜测订单是对还是错。
考虑到这一点,你至少可以做两件事。首先,是为参数提供有意义的名称,例如
float getTax( float price, float taxPercentage )
而不是
float getTax( float a, float b )
其次,在里面进行必要的检查:
float divide( float dividend, float divisor )
{
if( divisor == 0 )
{
throw "omg!";
}
}
可以进行更复杂的检查,例如制作仿函数,并明确设置它的参数,但在大多数情况下,只会使事情变得复杂而没有太多好处。