我正在设计库来为一台设备提供功能。该设备具有一些常用操作,但具有不同的算法来完成这些操作。我想要一个特定操作的一个函数原型,而不是一堆它们,而不是:
Alg1_Foo();
Alg2_Foo();
...
我想要这个:
Foo(alg);
但是我不想将alg作为单独的参数传递,因为即使没有它,函数也会有很多参数,它们将有参数用于识别和/或授权设备,参数,参数(至少其中之一),所以我认为将alg添加为单独的参数会很烦人。
所以我的想法是提供像这样的解决方案:
Foo(const SomeUnion& some_union);
其中:
union SomeUnion {
AlgId alg_id;
alg1::SomeStruct alg1_some_struct;
alg2::SomeStruct alg2_some_struct;
SomeUnion(alg1::SomeStruct some_struct) { alg1_some_struct = some_struct; };
SomeUnion(alg2::SomeStruct some_struct) { alg2_some_struct = some_struct; };
};
特定算法的结构如下:
namespace alg1 {
struct SomeStruct {
static const AlgId alg_id = ALG1;
. . .
};
}
因此,如果想要执行alg1,我们将适当的结构传递给Foo并且它在C ++中工作,比如说
alg1::SomeStruct a;
Foo(a);
但我希望我的图书馆能够保持纯C的可能性。当然,我需要:
删除引用并用指针替换它们;
删除命名空间(我们仍然可以在结构的帮助下模拟它们(这个帖子可能对那些感兴趣的人有用:Namespaces in C);
替换C ++ - 从C定义结构的样式,并在标记名称空间中定义名称(typedef struct tagStruct {...} Struct;);
从内部结构和联合中删除函数。
但是我无法理解是否有可能完成我想要做的维护C ...你看到了方法吗?或者将alg_id作为一个单独的参数传递而不是为了打扰工会和结构只是更简单(但我想尽可能避免它)?
答案 0 :(得分:3)
对我来说,这似乎是一个典型的案例,有人试图以“错误的方式”解决问题。
如果你有一个函数的“很多参数”,那么使用struct
就可以了。但是在struct
内隐藏“你实际上正在调用哪个函数”,然后在struct
内部有union
的几个变体,现在我们试图在一个函数中填充太多。开始分割函数,只需要一个struct
- 删除你的union
作为参数 - 这是错误的。 [我使用的代码与此类似的东西 - 潜入一些代码执行错误操作并导致一些难以找到错误的机会,因为你将错误类型的union
参数传递给函数使得这个真是个糟糕的解决方案]。如果将错误类型的结构传递给普通函数,编译器会告诉您。如果你填写了一个联合的错误部分,使用结构的“右”部分的代码将得到“奇怪的”数据[很可能是未定义的行为] - 这种类型的错误很难找到。
是的,分开你的功能,删除联盟!
修改强>
如果您希望拥有一个简单且一致的接口,那么您会想到一个建议:您有一个工厂函数,它将alg_id
传递给它,它返回一个指向相关函数的函数指针。不幸的是,如果每个函数的接口都是我建议的,不同的结构,那么你仍然有可能混淆数据结构和函数,但它确实减少了“已发布函数”的数量 - 事实上,这些函数不需要在提供它们的模块[库甚至对象文件]之外都可见。